Teach "git p4" to notice "Jobs:" in the log message and relay it to
Perforce to trigger its "jobs" support.

# By Pete Wyckoff
* pw/git-p4-jobs:
  git p4: notice Jobs lines in git commit messages
  git p4 test: refactor marshal_dump
  git p4: remove unused P4Submit interactive setting
This commit is contained in:
Junio C Hamano 2012-07-13 21:22:12 -07:00
Родитель f06d47e7e0 f19cb0a0e8
Коммит 7bdb74868c
4 изменённых файлов: 272 добавлений и 87 удалений

Просмотреть файл

@ -844,7 +844,6 @@ class P4Submit(Command, P4UserMap):
] ]
self.description = "Submit changes from git to the perforce depot." self.description = "Submit changes from git to the perforce depot."
self.usage += " [name of git branch to submit into perforce depot]" self.usage += " [name of git branch to submit into perforce depot]"
self.interactive = True
self.origin = "" self.origin = ""
self.detectRenames = False self.detectRenames = False
self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true" self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true"
@ -855,9 +854,34 @@ class P4Submit(Command, P4UserMap):
if len(p4CmdList("opened ...")) > 0: if len(p4CmdList("opened ...")) > 0:
die("You have files opened with perforce! Close them before starting the sync.") die("You have files opened with perforce! Close them before starting the sync.")
# replaces everything between 'Description:' and the next P4 submit template field with the def separate_jobs_from_description(self, message):
# commit message """Extract and return a possible Jobs field in the commit
def prepareLogMessage(self, template, message): message. It goes into a separate section in the p4 change
specification.
A jobs line starts with "Jobs:" and looks like a new field
in a form. Values are white-space separated on the same
line or on following lines that start with a tab.
This does not parse and extract the full git commit message
like a p4 form. It just sees the Jobs: line as a marker
to pass everything from then on directly into the p4 form,
but outside the description section.
Return a tuple (stripped log message, jobs string)."""
m = re.search(r'^Jobs:', message, re.MULTILINE)
if m is None:
return (message, None)
jobtext = message[m.start():]
stripped_message = message[:m.start()].rstrip()
return (stripped_message, jobtext)
def prepareLogMessage(self, template, message, jobs):
"""Edits the template returned from "p4 change -o" to insert
the message in the Description field, and the jobs text in
the Jobs field."""
result = "" result = ""
inDescriptionSection = False inDescriptionSection = False
@ -870,6 +894,9 @@ class P4Submit(Command, P4UserMap):
if inDescriptionSection: if inDescriptionSection:
if line.startswith("Files:") or line.startswith("Jobs:"): if line.startswith("Files:") or line.startswith("Jobs:"):
inDescriptionSection = False inDescriptionSection = False
# insert Jobs section
if jobs:
result += jobs + "\n"
else: else:
continue continue
else: else:
@ -981,7 +1008,13 @@ class P4Submit(Command, P4UserMap):
return 0 return 0
def prepareSubmitTemplate(self): def prepareSubmitTemplate(self):
# remove lines in the Files section that show changes to files outside the depot path we're committing into """Run "p4 change -o" to grab a change specification template.
This does not use "p4 -G", as it is nice to keep the submission
template in original order, since a human might edit it.
Remove lines in the Files section that show changes to files
outside the depot path we're committing into."""
template = "" template = ""
inFilesSection = False inFilesSection = False
for line in p4_read_pipe_lines(['change', '-o']): for line in p4_read_pipe_lines(['change', '-o']):
@ -1206,11 +1239,10 @@ class P4Submit(Command, P4UserMap):
logMessage = extractLogMessageFromGitCommit(id) logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.strip() logMessage = logMessage.strip()
(logMessage, jobs) = self.separate_jobs_from_description(logMessage)
template = self.prepareSubmitTemplate() template = self.prepareSubmitTemplate()
submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
if self.interactive:
submitTemplate = self.prepareLogMessage(template, logMessage)
if self.preserveUser: if self.preserveUser:
submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User) submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User)
@ -1281,14 +1313,6 @@ class P4Submit(Command, P4UserMap):
os.remove(f) os.remove(f)
os.remove(fileName) os.remove(fileName)
else:
fileName = "submit.txt"
file = open(fileName, "w+")
file.write(self.prepareLogMessage(template, logMessage))
file.close()
print ("Perforce submit template written as %s. "
+ "Please review/edit and then use p4 submit -i < %s to submit directly!"
% (fileName, fileName))
# Export git tags as p4 labels. Create a p4 label and then tag # Export git tags as p4 labels. Create a p4 label and then tag
# with that. # with that.
@ -1437,8 +1461,6 @@ class P4Submit(Command, P4UserMap):
commit = commits[0] commit = commits[0]
commits = commits[1:] commits = commits[1:]
self.applyCommit(commit) self.applyCommit(commit)
if not self.interactive:
break
if len(commits) == 0: if len(commits) == 0:
print "All changes applied!" print "All changes applied!"

Просмотреть файл

@ -102,3 +102,16 @@ cleanup_git() {
rm -rf "$git" && rm -rf "$git" &&
mkdir "$git" mkdir "$git"
} }
marshal_dump() {
what=$1 &&
line=${2:-1} &&
cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF &&
import marshal
import sys
for i in range($line):
d = marshal.load(sys.stdin)
print d['$what']
EOF
"$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
}

Просмотреть файл

@ -155,11 +155,6 @@ test_expect_success 'clone bare' '
) )
' '
marshal_dump() {
what=$1
"$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]'
}
# Sleep a bit so that the top-most p4 change did not happen "now". Then # Sleep a bit so that the top-most p4 change did not happen "now". Then
# import the repo and make sure that the initial import has the same time # import the repo and make sure that the initial import has the same time
# as the top-most change. # as the top-most change.

Просмотреть файл

@ -182,6 +182,161 @@ test_expect_success 'submit rename' '
) )
' '
#
# Converting git commit message to p4 change description, including
# parsing out the optional Jobs: line.
#
test_expect_success 'simple one-line description' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo desc2 >desc2 &&
git add desc2 &&
cat >msg <<-EOF &&
One-line description line for desc2.
EOF
git commit -F - <msg &&
git config git-p4.skipSubmitEdit true &&
git p4 submit &&
change=$(p4 -G changes -m 1 //depot/... | \
marshal_dump change) &&
# marshal_dump always adds a newline
p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
test_cmp msg pmsg
)
'
test_expect_success 'description with odd formatting' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo desc3 >desc3 &&
git add desc3 &&
(
printf "subject line\n\n\tExtra tab\nline.\n\n" &&
printf "Description:\n\tBogus description marker\n\n" &&
# git commit eats trailing newlines; only use one
printf "Files:\n\tBogus descs marker\n"
) >msg &&
git commit -F - <msg &&
git config git-p4.skipSubmitEdit true &&
git p4 submit &&
change=$(p4 -G changes -m 1 //depot/... | \
marshal_dump change) &&
# marshal_dump always adds a newline
p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
test_cmp msg pmsg
)
'
make_job() {
name="$1" &&
tab="$(printf \\t)" &&
p4 job -o | \
sed -e "/^Job:/s/.*/Job: $name/" \
-e "/^Description/{ n; s/.*/$tab job text/; }" | \
p4 job -i
}
test_expect_success 'description with Jobs section at end' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo desc4 >desc4 &&
git add desc4 &&
echo 6060842 >jobname &&
(
printf "subject line\n\n\tExtra tab\nline.\n\n" &&
printf "Files:\n\tBogus files marker\n" &&
printf "Junk: 3164175\n" &&
printf "Jobs: $(cat jobname)\n"
) >msg &&
git commit -F - <msg &&
git config git-p4.skipSubmitEdit true &&
# build a job
make_job $(cat jobname) &&
git p4 submit &&
change=$(p4 -G changes -m 1 //depot/... | \
marshal_dump change) &&
# marshal_dump always adds a newline
p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
# make sure Jobs line and all following is gone
sed "/^Jobs:/,\$d" msg >jmsg &&
test_cmp jmsg pmsg &&
# make sure p4 knows about job
p4 -G describe $change | marshal_dump job0 >job0 &&
test_cmp jobname job0
)
'
test_expect_success 'description with Jobs and values on separate lines' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo desc5 >desc5 &&
git add desc5 &&
echo PROJ-6060842 >jobname1 &&
echo PROJ-6060847 >jobname2 &&
(
printf "subject line\n\n\tExtra tab\nline.\n\n" &&
printf "Files:\n\tBogus files marker\n" &&
printf "Junk: 3164175\n" &&
printf "Jobs:\n" &&
printf "\t$(cat jobname1)\n" &&
printf "\t$(cat jobname2)\n"
) >msg &&
git commit -F - <msg &&
git config git-p4.skipSubmitEdit true &&
# build two jobs
make_job $(cat jobname1) &&
make_job $(cat jobname2) &&
git p4 submit &&
change=$(p4 -G changes -m 1 //depot/... | \
marshal_dump change) &&
# marshal_dump always adds a newline
p4 -G describe $change | marshal_dump desc | sed \$d >pmsg &&
# make sure Jobs line and all following is gone
sed "/^Jobs:/,\$d" msg >jmsg &&
test_cmp jmsg pmsg &&
# make sure p4 knows about the two jobs
p4 -G describe $change >change &&
(
marshal_dump job0 <change &&
marshal_dump job1 <change
) | sort >jobs &&
cat jobname1 jobname2 | sort >expected &&
test_cmp expected jobs
)
'
test_expect_success 'description with Jobs section and bogus following text' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo desc6 >desc6 &&
git add desc6 &&
echo 6060843 >jobname &&
(
printf "subject line\n\n\tExtra tab\nline.\n\n" &&
printf "Files:\n\tBogus files marker\n" &&
printf "Junk: 3164175\n" &&
printf "Jobs: $(cat jobname)\n" &&
printf "MoreJunk: 3711\n"
) >msg &&
git commit -F - <msg &&
git config git-p4.skipSubmitEdit true &&
# build a job
make_job $(cat jobname) &&
test_must_fail git p4 submit 2>err &&
test_i18ngrep "Unknown field name" err
)
'
test_expect_success 'kill p4d' ' test_expect_success 'kill p4d' '
kill_p4d kill_p4d
' '