Use three separate jobs for code coverage diffing

Reusable roles and playbooks are quite important upstream (I have
zuul-jobs inclusion in mind). Besides that, in Zuul's Ansible a playbook
is supposed to come from the same repo as the one where the job
definition is placed, and one can only override a job's `run` playbook.
This makes it rather annoying to modify, say, `tox-coverage` definition.

My previous approach with a job which performed two things (build the
old source *and* then generate coverage report) also would not scale
that well if the build+test phase is long.

Switch to three jobs:

- build the current, proposed state, and gather coverage info,
- build the past state, gather coverage info,
- download two artifacts from previous runs, reproduce the source trees,
and generate the final coverage diff report.

See-also: https://review.gerrithub.io/c/Telecominfraproject/oopt-zuul-jobs/+/489964
Change-Id: I6eb61669c6f28440a55ba08569a4f2683513a9fa
diff --git a/roles/download-next-coverage/tasks/download.yaml b/roles/download-coverage/tasks/download.yaml
similarity index 81%
rename from roles/download-next-coverage/tasks/download.yaml
rename to roles/download-coverage/tasks/download.yaml
index f5b2d45..576aeb7 100644
--- a/roles/download-next-coverage/tasks/download.yaml
+++ b/roles/download-coverage/tasks/download.yaml
@@ -5,4 +5,4 @@
 - name: Download one artifact
   get_url:
     url: "{{ artifact.url }}"
-    dest: "{{ new_source_prefix }}/coverage.xml"
+    dest: "{{ coverage_destination }}"
diff --git a/roles/download-coverage/tasks/main.yaml b/roles/download-coverage/tasks/main.yaml
new file mode 100644
index 0000000..8ae4695
--- /dev/null
+++ b/roles/download-coverage/tasks/main.yaml
@@ -0,0 +1,7 @@
+- name: Retrieve coverage from parent jobs
+  include_tasks: download.yaml
+  loop: "{{ zuul.artifacts | json_query(artifact_selector) }}"
+  vars:
+    artifact_selector: "[([?metadata.type == 'cobertura_xml' && project == '{{ zuul.project.name }}' && job == '{{ job_name }}'])[-1]]"
+  loop_control:
+    loop_var: artifact
diff --git a/roles/download-next-coverage/tasks/main.yaml b/roles/download-next-coverage/tasks/main.yaml
deleted file mode 100644
index ae7cbfd..0000000
--- a/roles/download-next-coverage/tasks/main.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-- name: Place for new version of sources
-  file:
-    path: "{{ new_source_prefix }}"
-    state: directory
-
-- name: Prepare copy of the new version of sources
-  command: git worktree add {{ new_source_prefix }}/{{ zuul.project.short_name }} {{ zuul.branch }}
-  args:
-    chdir: "{{ zuul.project.src_dir }}"
-
-- name: Retrieve coverage from parent jobs
-  include_tasks: download.yaml
-  loop: "{{ zuul.artifacts | json_query(artifact_seletcor) }}"
-  vars:
-    artifact_seletcor: "[([?metadata.type == 'cobertura_xml' && project == '{{ zuul.project.name }}'])[-1]]"
-  loop_control:
-    loop_var: artifact
diff --git a/roles/ensure-pycobertura/tasks/main.yaml b/roles/ensure-pycobertura/tasks/main.yaml
index 473d543..ab309bd 100644
--- a/roles/ensure-pycobertura/tasks/main.yaml
+++ b/roles/ensure-pycobertura/tasks/main.yaml
@@ -1,4 +1,4 @@
 - name: Ensure pycobertura is available
   pip:
     name: pycobertura
-    extra_args: --user
+  become: yes
diff --git a/roles/fetch-coverage-diff/tasks/main.yaml b/roles/fetch-coverage-diff/tasks/main.yaml
new file mode 100644
index 0000000..0e7ce70
--- /dev/null
+++ b/roles/fetch-coverage-diff/tasks/main.yaml
@@ -0,0 +1,34 @@
+- name: Check for coverage-diff.html
+  stat:
+    path: "{{ ansible_user_dir }}/zuul-output/logs/coverage-diff.html"
+    get_checksum: false
+    get_mime: false
+    get_md5: false
+  register: coverage_diff_html_stat
+
+- name: Register current coverage report as an artifact
+  when: coverage_diff_html_stat.stat.exists
+  zuul_return:
+    data:
+      zuul:
+        artifacts:
+          - name: "Full coverage report (current)"
+            url: "coverage-current.html"
+
+- name: Register previous coverage report as an artifact
+  when: coverage_diff_html_stat.stat.exists
+  zuul_return:
+    data:
+      zuul:
+        artifacts:
+          - name: "Full coverage report (previous)"
+            url: "coverage-previous.html"
+
+- name: Register coverage report diff as an artifact
+  when: coverage_diff_html_stat.stat.exists
+  zuul_return:
+    data:
+      zuul:
+        artifacts:
+          - name: "Coverage report: difference in coverage"
+            url: "coverage-diff.html"
diff --git a/roles/fetch-coverage-xml/defaults/main.yaml b/roles/fetch-coverage-xml/defaults/main.yaml
new file mode 100644
index 0000000..2f1e36d
--- /dev/null
+++ b/roles/fetch-coverage-xml/defaults/main.yaml
@@ -0,0 +1 @@
+coverage_artifact_name: "Coverage data"
diff --git a/roles/fetch-coverage-xml/tasks/main.yaml b/roles/fetch-coverage-xml/tasks/main.yaml
index c247e49..5316a35 100644
--- a/roles/fetch-coverage-xml/tasks/main.yaml
+++ b/roles/fetch-coverage-xml/tasks/main.yaml
@@ -25,7 +25,7 @@
     data:
       zuul:
         artifacts:
-          - name: "Coverage data"
+          - name: "{{ coverage_artifact_name }}"
             metadata:
               type: "cobertura_xml"
             url: "coverage.xml"
diff --git a/roles/git-use-previous-commit/tasks/main.yaml b/roles/git-use-previous-commit/tasks/main.yaml
index cb7458e..db63a97 100644
--- a/roles/git-use-previous-commit/tasks/main.yaml
+++ b/roles/git-use-previous-commit/tasks/main.yaml
@@ -1,7 +1,8 @@
 - name: Prepare git submodules
   shell: |
-    echo "{{ item.key }}"
-    git checkout -b "zuul_origin_{{ zuul.branch }}" "origin/{{ zuul.branch }}"
+    PREVIOUS_BRANCH=$(git rev-parse --abbrev-ref HEAD)
+    echo "{{ item.key }}: ${PREVIOUS_BRANCH}"
+    git checkout -b zuul_origin_${PREVIOUS_BRANCH} origin/${PREVIOUS_BRANCH}
   args:
     chdir: "{{ ansible_user_dir }}/{{ item.value.src_dir }}"
   loop: "{{ query('dict', zuul.projects) }}"
diff --git a/roles/prepare-previous-src/tasks/main.yaml b/roles/prepare-previous-src/tasks/main.yaml
new file mode 100644
index 0000000..250d40d
--- /dev/null
+++ b/roles/prepare-previous-src/tasks/main.yaml
@@ -0,0 +1,9 @@
+- name: Place for previous version of sources
+  file:
+    path: "{{ (previous_source_prefix + '/' + zuul.project.canonical_hostname + '/' + zuul.project.name) | dirname }}"
+    state: directory
+
+- name: Prepare copy of the previous version of sources
+  shell:
+    cmd: git worktree add {{ previous_source_prefix }}/{{ zuul.project.canonical_hostname }}/{{ zuul.project.name }} origin/$(git rev-parse --abbrev-ref HEAD)
+    chdir: "{{ zuul.project.src_dir }}"
diff --git a/roles/pycobertura-diff/tasks/main.yaml b/roles/pycobertura-diff/tasks/main.yaml
index 418b273..471c22e 100644
--- a/roles/pycobertura-diff/tasks/main.yaml
+++ b/roles/pycobertura-diff/tasks/main.yaml
@@ -1,45 +1,18 @@
 - name: Generate pycobertura report
   shell: |
     set -ex
-    PATH=${PATH}:~/.local/bin
-    pycobertura show --format html --output "{{ ansible_user_dir }}/zuul-output/logs/coverage.html" \
-      --source "{{ new_source_prefix }}/{{ zuul.project.short_name }}" "{{ new_source_prefix }}/coverage.xml"
+
+    pycobertura show --format html --output "{{ ansible_user_dir }}/zuul-output/logs/coverage-previous.html" \
+      --source "{{ previous_source_prefix }}/{{ zuul.project.canonical_hostname }}/{{ zuul.project.name}}" \
+      "{{ ansible_user_dir }}/coverage-previous.xml"
+
+    pycobertura show --format html --output "{{ ansible_user_dir }}/zuul-output/logs/coverage-current.html" \
+      --source "{{ zuul.project.src_dir }}" \
+      "{{ ansible_user_dir }}/coverage-current.xml"
+
     pycobertura diff --format html --output "{{ ansible_user_dir }}/zuul-output/logs/coverage-diff.html" \
-      --source1 "{{ zuul.project.src_dir }}" "{{ coverage_xml_dir }}/coverage.xml" \
-      --source2 "{{ new_source_prefix }}/{{ zuul.project.short_name }}" "{{ new_source_prefix }}/coverage.xml"
-    sed -e 's;^  </body>$;    <p>Show <a href="coverage.html">final coverage</a> only</p>\n  </body>;' \
-      -i "{{ ansible_user_dir }}/zuul-output/logs/coverage-diff.html"
+      --source1 "{{ previous_source_prefix }}/{{ zuul.project.canonical_hostname }}/{{ zuul.project.name}}" "{{ ansible_user_dir }}/coverage-previous.xml" \
+      --source2 "{{ zuul.project.src_dir }}" "{{ ansible_user_dir }}/coverage-current.xml"
 
-- name: Check for coverage-diff.html
-  stat:
-    path: "{{ ansible_user_dir }}/zuul-output/logs/coverage-diff.html"
-    get_checksum: false
-    get_mime: false
-    get_md5: false
-  register: coverage_diff_html_stat
-
-- name: Check for coverage.html
-  stat:
-    path: "{{ ansible_user_dir }}/zuul-output/logs/coverage.html"
-    get_checksum: false
-    get_mime: false
-    get_md5: false
-  register: coverage_html_stat
-
-- name: Register coverage reports as artifacts
-  when: coverage_html_stat.stat.exists
-  zuul_return:
-    data:
-      zuul:
-        artifacts:
-          - name: "Full coverage report"
-            url: "coverage.html"
-
-- name: Register coverage reports as artifacts
-  when: coverage_diff_html_stat.stat.exists
-  zuul_return:
-    data:
-      zuul:
-        artifacts:
-          - name: "Change of code coverage report"
-            url: "coverage-diff.html"
+    sed -e 's;^  </body>$;    <p>Show <a href="coverage-current.html">previous</a> or <a href="coverage-current.html">final coverage</a> only</p>\n  </body>;' \
+      -i "{{ ansible_user_dir }}/zuul-output/logs/coverage-diff.html" || true