git p4: notice Jobs lines in git commit messages
P4 has a feature called "jobs" that allows linking changes to a bug tracking system or other tasks. When submitting code, a job name can be specified to mark that this change is associated with a particular job. Teach git-p4 to find an optional "Jobs:" line in git commit messages and use them to make a Jobs section in the p4 change specifitation. Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pete Wyckoff committed
Jul 4, 2012 at 09:34 UTC
f19cb0a0e80e094970cfa854dc3da60c927830eb
2 files changed
+195
-6
git-p4.py
+40
-6
@@ -854,9 +854,34 @@ class P4Submit(Command, P4UserMap):
854
if len(p4CmdList("opened ...")) > 0:
855
die("You have files opened with perforce! Close them before starting the sync.")
856
857
- # replaces everything between 'Description:' and the next P4 submit template field with the
858
- # commit message
859
- def prepareLogMessage(self, template, message):
857
+ def separate_jobs_from_description(self, message):
858
+ """Extract and return a possible Jobs field in the commit
859
+ message. It goes into a separate section in the p4 change
860
+ specification.
861
+
862
+ A jobs line starts with "Jobs:" and looks like a new field
863
+ in a form. Values are white-space separated on the same
864
+ line or on following lines that start with a tab.
865
+
866
+ This does not parse and extract the full git commit message
867
+ like a p4 form. It just sees the Jobs: line as a marker
868
+ to pass everything from then on directly into the p4 form,
869
+ but outside the description section.
870
+
871
+ Return a tuple (stripped log message, jobs string)."""
872
+
873
+ m = re.search(r'^Jobs:', message, re.MULTILINE)
874
+ if m is None:
875
+ return (message, None)
876
+
877
+ jobtext = message[m.start():]
878
+ stripped_message = message[:m.start()].rstrip()
879
+ return (stripped_message, jobtext)
880
+
881
+ def prepareLogMessage(self, template, message, jobs):
882
+ """Edits the template returned from "p4 change -o" to insert
883
+ the message in the Description field, and the jobs text in
884
+ the Jobs field."""
885
result = ""
886
887
inDescriptionSection = False
@@ -869,6 +894,9 @@ class P4Submit(Command, P4UserMap):
894
if inDescriptionSection:
895
if line.startswith("Files:") or line.startswith("Jobs:"):
896
inDescriptionSection = False
897
+ # insert Jobs section
898
+ if jobs:
899
+ result += jobs + "\n"
900
else:
901
continue
902
else:
@@ -980,7 +1008,13 @@ class P4Submit(Command, P4UserMap):
1008
return 0
1009
1010
def prepareSubmitTemplate(self):
983
- # remove lines in the Files section that show changes to files outside the depot path we're committing into
1011
+ """Run "p4 change -o" to grab a change specification template.
1012
+ This does not use "p4 -G", as it is nice to keep the submission
1013
+ template in original order, since a human might edit it.
1014
+
1015
+ Remove lines in the Files section that show changes to files
1016
+ outside the depot path we're committing into."""
1017
+
1018
template = ""
1019
inFilesSection = False
1020
for line in p4_read_pipe_lines(['change', '-o']):
@@ -1205,10 +1239,10 @@ class P4Submit(Command, P4UserMap):
1239
1240
logMessage = extractLogMessageFromGitCommit(id)
1241
logMessage = logMessage.strip()
1242
+ (logMessage, jobs) = self.separate_jobs_from_description(logMessage)
1243
1244
template = self.prepareSubmitTemplate()
1210
-
1211
- submitTemplate = self.prepareLogMessage(template, logMessage)
1245
+ submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
1246
1247
if self.preserveUser:
1248
submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User)
t/t9807-git-p4-submit.sh
+155
@@ -182,6 +182,161 @@ test_expect_success 'submit rename' '
182
)
183
'
184
185
+#
186
+# Converting git commit message to p4 change description, including
187
+# parsing out the optional Jobs: line.
188
+#
189
+test_expect_success 'simple one-line description' '
190
+ test_when_finished cleanup_git &&
191
+ git p4 clone --dest="$git" //depot &&
192
+ (
193
+ cd "$git" &&
194
+ echo desc2 >desc2 &&
195
+ git add desc2 &&
196
+ cat >msg <<-EOF &&
197
+ One-line description line for desc2.
198
+ EOF
199
+ git commit -F - <msg &&
200
+ git config git-p4.skipSubmitEdit true &&
201
+ git p4 submit &&
202
+ change=$(p4 -G changes -m 1 //depot/... | \
203
+ marshal_dump change) &&
204
+ # marshal_dump always adds a newline
205
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
206
+ test_cmp msg pmsg
207
+ )
208
+'
209
+
210
+test_expect_success 'description with odd formatting' '
211
+ test_when_finished cleanup_git &&
212
+ git p4 clone --dest="$git" //depot &&
213
+ (
214
+ cd "$git" &&
215
+ echo desc3 >desc3 &&
216
+ git add desc3 &&
217
+ (
218
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
219
+ printf "Description:\n\tBogus description marker\n\n" &&
220
+ # git commit eats trailing newlines; only use one
221
+ printf "Files:\n\tBogus descs marker\n"
222
+ ) >msg &&
223
+ git commit -F - <msg &&
224
+ git config git-p4.skipSubmitEdit true &&
225
+ git p4 submit &&
226
+ change=$(p4 -G changes -m 1 //depot/... | \
227
+ marshal_dump change) &&
228
+ # marshal_dump always adds a newline
229
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
230
+ test_cmp msg pmsg
231
+ )
232
+'
233
+
234
+make_job() {
235
+ name="$1" &&
236
+ tab="$(printf \\t)" &&
237
+ p4 job -o | \
238
+ sed -e "/^Job:/s/.*/Job: $name/" \
239
+ -e "/^Description/{ n; s/.*/$tab job text/; }" | \
240
+ p4 job -i
241
+}
242
+
243
+test_expect_success 'description with Jobs section at end' '
244
+ test_when_finished cleanup_git &&
245
+ git p4 clone --dest="$git" //depot &&
246
+ (
247
+ cd "$git" &&
248
+ echo desc4 >desc4 &&
249
+ git add desc4 &&
250
+ echo 6060842 >jobname &&
251
+ (
252
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
253
+ printf "Files:\n\tBogus files marker\n" &&
254
+ printf "Junk: 3164175\n" &&
255
+ printf "Jobs: $(cat jobname)\n"
256
+ ) >msg &&
257
+ git commit -F - <msg &&
258
+ git config git-p4.skipSubmitEdit true &&
259
+ # build a job
260
+ make_job $(cat jobname) &&
261
+ git p4 submit &&
262
+ change=$(p4 -G changes -m 1 //depot/... | \
263
+ marshal_dump change) &&
264
+ # marshal_dump always adds a newline
265
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
266
+ # make sure Jobs line and all following is gone
267
+ sed "/^Jobs:/,\$d" msg >jmsg &&
268
+ test_cmp jmsg pmsg &&
269
+ # make sure p4 knows about job
270
+ p4 -G describe $change | marshal_dump job0 >job0 &&
271
+ test_cmp jobname job0
272
+ )
273
+'
274
+
275
+test_expect_success 'description with Jobs and values on separate lines' '
276
+ test_when_finished cleanup_git &&
277
+ git p4 clone --dest="$git" //depot &&
278
+ (
279
+ cd "$git" &&
280
+ echo desc5 >desc5 &&
281
+ git add desc5 &&
282
+ echo PROJ-6060842 >jobname1 &&
283
+ echo PROJ-6060847 >jobname2 &&
284
+ (
285
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
286
+ printf "Files:\n\tBogus files marker\n" &&
287
+ printf "Junk: 3164175\n" &&
288
+ printf "Jobs:\n" &&
289
+ printf "\t$(cat jobname1)\n" &&
290
+ printf "\t$(cat jobname2)\n"
291
+ ) >msg &&
292
+ git commit -F - <msg &&
293
+ git config git-p4.skipSubmitEdit true &&
294
+ # build two jobs
295
+ make_job $(cat jobname1) &&
296
+ make_job $(cat jobname2) &&
297
+ git p4 submit &&
298
+ change=$(p4 -G changes -m 1 //depot/... | \
299
+ marshal_dump change) &&
300
+ # marshal_dump always adds a newline
301
+ p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
302
+ # make sure Jobs line and all following is gone
303
+ sed "/^Jobs:/,\$d" msg >jmsg &&
304
+ test_cmp jmsg pmsg &&
305
+ # make sure p4 knows about the two jobs
306
+ p4 -G describe $change >change &&
307
+ (
308
+ marshal_dump job0 <change &&
309
+ marshal_dump job1 <change
310
+ ) | sort >jobs &&
311
+ cat jobname1 jobname2 | sort >expected &&
312
+ test_cmp expected jobs
313
+ )
314
+'
315
+
316
+test_expect_success 'description with Jobs section and bogus following text' '
317
+ test_when_finished cleanup_git &&
318
+ git p4 clone --dest="$git" //depot &&
319
+ (
320
+ cd "$git" &&
321
+ echo desc6 >desc6 &&
322
+ git add desc6 &&
323
+ echo 6060843 >jobname &&
324
+ (
325
+ printf "subject line\n\n\tExtra tab\nline.\n\n" &&
326
+ printf "Files:\n\tBogus files marker\n" &&
327
+ printf "Junk: 3164175\n" &&
328
+ printf "Jobs: $(cat jobname)\n" &&
329
+ printf "MoreJunk: 3711\n"
330
+ ) >msg &&
331
+ git commit -F - <msg &&
332
+ git config git-p4.skipSubmitEdit true &&
333
+ # build a job
334
+ make_job $(cat jobname) &&
335
+ test_must_fail git p4 submit 2>err &&
336
+ test_i18ngrep "Unknown field name" err
337
+ )
338
+'
339
+
340
test_expect_success 'kill p4d' '
341
kill_p4d
342
'