{"thread":{"id":"42077","subject":"[PATCH v3 2/2] git-p4: add P4 jobs to git commit message","startedAt":"2016-04-19T19:49:41Z","lastAt":"2016-04-19T19:49:41Z","messageCount":2,"participants":["Jan Durovec"],"isPatch":true,"patchVersion":3,"patchTotal":2},"messages":[{"id":"283838","messageId":"01020154301239b6-f5b2b329-78f7-43c0-ab5c-2644994511c4-000000@eu-west-1.amazonses.com","threadId":"42077","inReplyTo":"01020154301238e9-9d46ac5b-d6e6-4c44-9d2f-7859e0339158-000000@eu-west-1.amazonses.com","subject":"[PATCH v3 2/2] git-p4: add P4 jobs to git commit message","fromName":"Jan Durovec","fromEmail":"jan.durovec@gmail.com","sentAt":"2016-04-19T19:49:41Z","receivedAt":"2016-04-19T19:49:41Z","isPatch":true,"sender":{"key":"jan.durovec@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16178826?v=4"},"body":"When migrating from Perforce to git the information about P4 jobs\nassociated with P4 changelists is lost.\n\nHaving these jobs listed on messages of related git commits enables smooth\nmigration for projects that take advantage of e.g. JIRA integration\n(which uses jobs on Perforce side and parses commit messages on git side).\n\nThe jobs are added to the message in the same format as is expected when\nmigrating in the reverse direction.\n\nSigned-off-by: Jan Durovec <jan.durovec@gmail.com>\n---\n git-p4.py              | 12 ++++++\n t/lib-git-p4.sh        |  9 +++++\n t/t9829-git-p4-jobs.sh | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 120 insertions(+)\n create mode 100755 t/t9829-git-p4-jobs.sh\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 527d44b..8f869d7 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2320,6 +2320,15 @@ def extractFilesFromCommit(self, commit):\n             fnum = fnum + 1\n         return files\n \n+    def extractJobsFromCommit(self, commit):\n+        jobs = []\n+        jnum = 0\n+        while commit.has_key(\"job%s\" % jnum):\n+            job = commit[\"job%s\" % jnum]\n+            jobs.append(job)\n+            jnum = jnum + 1\n+        return jobs\n+\n     def stripRepoPath(self, path, prefixes):\n         \"\"\"When streaming files, this is called to map a p4 depot path\n            to where it should go in git.  The prefixes are either\n@@ -2665,6 +2674,7 @@ def hasBranchPrefix(self, path):\n     def commit(self, details, files, branch, parent = \"\"):\n         epoch = details[\"time\"]\n         author = details[\"user\"]\n+        jobs = self.extractJobsFromCommit(details)\n \n         if self.verbose:\n             print('commit into {0}'.format(branch))\n@@ -2692,6 +2702,8 @@ def commit(self, details, files, branch, parent = \"\"):\n \n         self.gitStream.write(\"data <<EOT\\n\")\n         self.gitStream.write(details[\"desc\"])\n+        if len(jobs) > 0:\n+            self.gitStream.write(\"\\nJobs: %s\" % (' '.join(jobs)))\n         self.gitStream.write(\"\\n[git-p4: depot-paths = \\\"%s\\\": change = %s\" %\n                              (','.join(self.branchPrefixes), details[\"change\"]))\n         if len(details['options']) > 0:\ndiff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh\nindex 0e59fd1..ce3536e 100644\n--- a/t/lib-git-p4.sh\n+++ b/t/lib-git-p4.sh\n@@ -160,6 +160,15 @@ p4_add_user () {\n \tEOF\n }\n \n+p4_add_job () {\n+\tp4 job -f -i <<-EOF\n+\tJob: $1\n+\tStatus: open\n+\tUser: dummy\n+\tDescription:\n+\tEOF\n+}\n+\n retry_until_success () {\n \ttimeout=$(($(time_in_seconds) + $RETRY_TIMEOUT))\n \tuntil \"$@\" 2>/dev/null || test $(time_in_seconds) -gt $timeout\ndiff --git a/t/t9829-git-p4-jobs.sh b/t/t9829-git-p4-jobs.sh\nnew file mode 100755\nindex 0000000..971aeee\n--- /dev/null\n+++ b/t/t9829-git-p4-jobs.sh\n@@ -0,0 +1,99 @@\n+#!/bin/sh\n+\n+test_description='git p4 retrieve job info'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tstart_p4d\n+'\n+\n+test_expect_success 'add p4 jobs' '\n+\t(\n+\t\tp4_add_job TESTJOB-A &&\n+\t\tp4_add_job TESTJOB-B\n+\t)\n+'\n+\n+test_expect_success 'add p4 files' '\n+\tclient_view \"//depot/... //client/...\" &&\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\t>file1 &&\n+\t\tp4 add file1 &&\n+\t\tp4 submit -d \"Add file 1\"\n+\t)\n+'\n+\n+test_expect_success 'check log message of changelist with no jobs' '\n+\tclient_view \"//depot/... //client/...\" &&\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tcd \"$git\" &&\n+\t\tgit init . &&\n+\t\tgit p4 clone --use-client-spec --destination=\"$git\" //depot@all &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tAdd file 1\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n+\n+\t\tEOF\n+\t\tgit log --format=%B >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add TESTJOB-A to change 1' '\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\tp4 fix -c 1 TESTJOB-A\n+\t)\n+'\n+\n+test_expect_success 'check log message of changelist with one job' '\n+\tclient_view \"//depot/... //client/...\" &&\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tcd \"$git\" &&\n+\t\tgit init . &&\n+\t\tgit p4 clone --use-client-spec --destination=\"$git\" //depot@all &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tAdd file 1\n+\t\tJobs: TESTJOB-A\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n+\n+\t\tEOF\n+\t\tgit log --format=%B >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'add TESTJOB-B to change 1' '\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\tp4 fix -c 1 TESTJOB-B\n+\t)\n+'\n+\n+test_expect_success 'check log message of changelist with more jobs' '\n+\tclient_view \"//depot/... //client/...\" &&\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tcd \"$git\" &&\n+\t\tgit init . &&\n+\t\tgit p4 clone --use-client-spec --destination=\"$git\" //depot@all &&\n+\t\tcat >expect <<-\\EOF &&\n+\t\tAdd file 1\n+\t\tJobs: TESTJOB-A TESTJOB-B\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n+\n+\t\tEOF\n+\t\tgit log --format=%B >actual &&\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n\n--\nhttps://github.com/git/git/pull/225\n"},{"id":"283839","messageId":"01020154301238e9-9d46ac5b-d6e6-4c44-9d2f-7859e0339158-000000@eu-west-1.amazonses.com","threadId":"42077","inReplyTo":null,"subject":"[PATCH v3 1/2] git-p4: clean-up code style in tests","fromName":"Jan Durovec","fromEmail":"jan.durovec@gmail.com","sentAt":"2016-04-19T19:49:41Z","receivedAt":"2016-04-19T19:49:41Z","isPatch":true,"sender":{"key":"jan.durovec@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16178826?v=4"},"body":"Preliminary clean-up of testing libraries for git-p4.\n\n* spaces added to both sides of () in function definitions in lib-git-p4\n* tab indentation added to git-p4 tests when <<- redirection is used\n\nSigned-off-by: Jan Durovec <jan.durovec@gmail.com>\n---\n t/lib-git-p4.sh                      | 24 +++++++--------\n t/t9826-git-p4-keep-empty-commits.sh | 60 ++++++++++++++++++------------------\n 2 files changed, 42 insertions(+), 42 deletions(-)\n\ndiff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh\nindex f9ae1d7..0e59fd1 100644\n--- a/t/lib-git-p4.sh\n+++ b/t/lib-git-p4.sh\n@@ -33,7 +33,7 @@ fi\n # Older versions of perforce were available compiled natively for\n # cygwin.  Those do not accept native windows paths, so make sure\n # not to convert for them.\n-native_path() {\n+native_path () {\n \tpath=\"$1\" &&\n \tif test_have_prereq CYGWIN && ! p4 -V | grep -q CYGWIN\n \tthen\n@@ -49,7 +49,7 @@ native_path() {\n # Attention: This function is not safe again against time offset updates\n # at runtime (e.g. via NTP). The 'clock_gettime(CLOCK_MONOTONIC)'\n # function could fix that but it is not in Python until 3.3.\n-time_in_seconds() {\n+time_in_seconds () {\n \tpython -c 'import time; print int(time.time())'\n }\n \n@@ -75,7 +75,7 @@ git=\"$TRASH_DIRECTORY/git\"\n pidfile=\"$TRASH_DIRECTORY/p4d.pid\"\n \n # Sometimes \"prove\" seems to hang on exit because p4d is still running\n-cleanup() {\n+cleanup () {\n \tif test -f \"$pidfile\"\n \tthen\n \t\tkill -9 $(cat \"$pidfile\") 2>/dev/null && exit 255\n@@ -89,7 +89,7 @@ trap cleanup EXIT\n TMPDIR=\"$TRASH_DIRECTORY\"\n export TMPDIR\n \n-start_p4d() {\n+start_p4d () {\n \tmkdir -p \"$db\" \"$cli\" \"$git\" &&\n \trm -f \"$pidfile\" &&\n \t(\n@@ -151,7 +151,7 @@ start_p4d() {\n \treturn 0\n }\n \n-p4_add_user() {\n+p4_add_user () {\n \tname=$1 &&\n \tp4 user -f -i <<-EOF\n \tUser: $name\n@@ -160,7 +160,7 @@ p4_add_user() {\n \tEOF\n }\n \n-retry_until_success() {\n+retry_until_success () {\n \ttimeout=$(($(time_in_seconds) + $RETRY_TIMEOUT))\n \tuntil \"$@\" 2>/dev/null || test $(time_in_seconds) -gt $timeout\n \tdo\n@@ -168,7 +168,7 @@ retry_until_success() {\n \tdone\n }\n \n-retry_until_fail() {\n+retry_until_fail () {\n \ttimeout=$(($(time_in_seconds) + $RETRY_TIMEOUT))\n \tuntil ! \"$@\" 2>/dev/null || test $(time_in_seconds) -gt $timeout\n \tdo\n@@ -176,7 +176,7 @@ retry_until_fail() {\n \tdone\n }\n \n-kill_p4d() {\n+kill_p4d () {\n \tpid=$(cat \"$pidfile\")\n \tretry_until_fail kill $pid\n \tretry_until_fail kill -9 $pid\n@@ -186,13 +186,13 @@ kill_p4d() {\n \tretry_until_fail kill -9 $watchdog_pid\n }\n \n-cleanup_git() {\n+cleanup_git () {\n \tretry_until_success rm -r \"$git\"\n \ttest_must_fail test -d \"$git\" &&\n \tretry_until_success mkdir \"$git\"\n }\n \n-marshal_dump() {\n+marshal_dump () {\n \twhat=$1 &&\n \tline=${2:-1} &&\n \tcat >\"$TRASH_DIRECTORY/marshal-dump.py\" <<-EOF &&\n@@ -208,7 +208,7 @@ marshal_dump() {\n #\n # Construct a client with this list of View lines\n #\n-client_view() {\n+client_view () {\n \t(\n \t\tcat <<-EOF &&\n \t\tClient: $P4CLIENT\n@@ -222,7 +222,7 @@ client_view() {\n \t) | p4 client -i\n }\n \n-is_cli_file_writeable() {\n+is_cli_file_writeable () {\n \t# cygwin version of p4 does not set read-only attr,\n \t# will be marked 444 but -w is true\n \tfile=\"$1\" &&\ndiff --git a/t/t9826-git-p4-keep-empty-commits.sh b/t/t9826-git-p4-keep-empty-commits.sh\nindex be12960..fa8b9da 100755\n--- a/t/t9826-git-p4-keep-empty-commits.sh\n+++ b/t/t9826-git-p4-keep-empty-commits.sh\n@@ -47,23 +47,23 @@ test_expect_success 'Clone repo root path with all history' '\n \t\tgit init . &&\n \t\tgit p4 clone --use-client-spec --destination=\"$git\" //depot@all &&\n \t\tcat >expect <<-\\EOF &&\n-Remove file 4\n-[git-p4: depot-paths = \"//depot/\": change = 6]\n+\t\tRemove file 4\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 6]\n \n-Remove file 3\n-[git-p4: depot-paths = \"//depot/\": change = 5]\n+\t\tRemove file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 5]\n \n-Add file 4\n-[git-p4: depot-paths = \"//depot/\": change = 4]\n+\t\tAdd file 4\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 4]\n \n-Add file 3\n-[git-p4: depot-paths = \"//depot/\": change = 3]\n+\t\tAdd file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 3]\n \n-Add file 2\n-[git-p4: depot-paths = \"//depot/\": change = 2]\n+\t\tAdd file 2\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 2]\n \n-Add file 1\n-[git-p4: depot-paths = \"//depot/\": change = 1]\n+\t\tAdd file 1\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n \n \t\tEOF\n \t\tgit log --format=%B >actual &&\n@@ -80,23 +80,23 @@ test_expect_success 'Clone repo subdir with all history but keep empty commits'\n \t\tgit config git-p4.keepEmptyCommits true &&\n \t\tgit p4 clone --use-client-spec --destination=\"$git\" //depot@all &&\n \t\tcat >expect <<-\\EOF &&\n-Remove file 4\n-[git-p4: depot-paths = \"//depot/\": change = 6]\n+\t\tRemove file 4\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 6]\n \n-Remove file 3\n-[git-p4: depot-paths = \"//depot/\": change = 5]\n+\t\tRemove file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 5]\n \n-Add file 4\n-[git-p4: depot-paths = \"//depot/\": change = 4]\n+\t\tAdd file 4\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 4]\n \n-Add file 3\n-[git-p4: depot-paths = \"//depot/\": change = 3]\n+\t\tAdd file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 3]\n \n-Add file 2\n-[git-p4: depot-paths = \"//depot/\": change = 2]\n+\t\tAdd file 2\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 2]\n \n-Add file 1\n-[git-p4: depot-paths = \"//depot/\": change = 1]\n+\t\tAdd file 1\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n \n \t\tEOF\n \t\tgit log --format=%B >actual &&\n@@ -112,14 +112,14 @@ test_expect_success 'Clone repo subdir with all history' '\n \t\tgit init . &&\n \t\tgit p4 clone --use-client-spec --destination=\"$git\" --verbose //depot@all &&\n \t\tcat >expect <<-\\EOF &&\n-Remove file 3\n-[git-p4: depot-paths = \"//depot/\": change = 5]\n+\t\tRemove file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 5]\n \n-Add file 3\n-[git-p4: depot-paths = \"//depot/\": change = 3]\n+\t\tAdd file 3\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 3]\n \n-Add file 1\n-[git-p4: depot-paths = \"//depot/\": change = 1]\n+\t\tAdd file 1\n+\t\t[git-p4: depot-paths = \"//depot/\": change = 1]\n \n \t\tEOF\n \t\tgit log --format=%B >actual &&\n\n--\nhttps://github.com/git/git/pull/225\n"}]}