From ca371480aa93de35c798f456d0d7af6e232b333e Mon Sep 17 00:00:00 2001
From: Niklas Dusenlund <niklas.dusenlund@bitbox.swiss>
Date: Sun, 18 Aug 2024 21:54:41 +0200
Subject: [PATCH] ci: Fix per commit CI

The pull request event does not have write access to the repo, so it
cannot dispatch jobs.
---
 .ci/matrix-from-commit-log      | 13 +++++++
 .github/workflows/commit-ci.yml | 61 -------------------------------
 .github/workflows/pr-ci.yml     | 64 ++++++++++++++++++++++++++-------
 3 files changed, 64 insertions(+), 74 deletions(-)
 create mode 100755 .ci/matrix-from-commit-log
 delete mode 100644 .github/workflows/commit-ci.yml

diff --git a/.ci/matrix-from-commit-log b/.ci/matrix-from-commit-log
new file mode 100755
index 0000000000..04a6083914
--- /dev/null
+++ b/.ci/matrix-from-commit-log
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+
+import subprocess
+import sys
+import json
+
+range = sys.argv[1]
+
+commits = subprocess.run(f'git log --format="%H" {range}', shell=True, text=True, capture_output=True)
+commits = commits.stdout.strip().split()
+
+if len(commits) > 0:
+  print(json.dumps({'commit': commits}))
diff --git a/.github/workflows/commit-ci.yml b/.github/workflows/commit-ci.yml
deleted file mode 100644
index 55d34d61b9..0000000000
--- a/.github/workflows/commit-ci.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-# See reference docs at
-# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
-name: Per commit CI
-on:
-  workflow_dispatch:
-    inputs:
-      sha:
-        description: Git commit to check
-        required: true
-      base_ref:
-        description: Base reference we are comparing against (e.g., 'master')
-        required: true
-
-jobs:
-  ci:
-    runs-on: ubuntu-22.04
-    steps:
-      - name: Set commit status to pending
-        run: |
-          curl -L -s \
-            -X POST \
-            -H "Accept: application/vnd.github+json" \
-            -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-            -H "X-GitHub-Api-Version: 2022-11-28" \
-            ${{ github.api_url }}/repos/${{ github.repository }}/statuses/${{ inputs.sha }} \
-            -d '{"state":"pending","target_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}","description":"The build started!","context":"ci / per-commit-build"}'
-
-      - name: Clone the repo
-        uses: actions/checkout@v4
-        with:
-          submodules: recursive
-          ref: ${{ inputs.base_ref }}
-
-      - name: Create merge commit
-        env:
-          GIT_AUTHOR_NAME: Bot
-          GIT_AUTHOR_EMAIL: bot@bitbox.swiss
-          GIT_COMMITTER_NAME: Bot
-          GIT_COMMITTER_EMAIL: bot@bitbox.swiss
-        run: |
-          git fetch origin ${{ inputs.sha }}
-          git merge --no-ff --no-edit ${{ inputs.sha }}
-          echo "merge commit parents:"
-          git log -1 --format=%P
-
-      - name: Pull container image
-        run: ./.ci/run-container-ci pull
-
-      - name: Run CI in container
-        run: ./.ci/run-container-ci ${{github.workspace}} ${{ inputs.base_ref }}
-
-      - name: Set status
-        if: always()
-        run: |
-          curl -L -s \
-            -X POST \
-            -H "Accept: application/vnd.github+json" \
-            -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-            -H "X-GitHub-Api-Version: 2022-11-28" \
-            ${{ github.api_url }}/repos/${{ github.repository }}/statuses/${{ inputs.sha }} \
-            -d '{"state":"${{job.status}}","target_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}","description":"The build ${{ job.status }}!","context":"ci / per-commit-build"}'
diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml
index 99fea29186..34f17f8d54 100644
--- a/.github/workflows/pr-ci.yml
+++ b/.github/workflows/pr-ci.yml
@@ -1,31 +1,69 @@
 # See reference docs at
 # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
+
 name: Pull request CI
 on: pull_request
 
 jobs:
-  pr-ci:
+  pr-head-ci:
     runs-on: ubuntu-22.04
     steps:
       - name: Clone the repo
         uses: actions/checkout@v4
         with:
           submodules: recursive
+
+      - name: Pull container image
+        run: ./.ci/run-container-ci pull
+
+      - name: Run CI in container
+        run: ./.ci/run-container-ci ${{github.workspace}} ${{ github.base_ref }}
+
+  # Generate a list of commits to run CI on
+  generate-matrix:
+    runs-on: ubuntu-22.04
+    outputs:
+      matrix: ${{ steps.set-matrix.outputs.matrix }}
+    steps:
+      - name: Clone the repo
+        uses: actions/checkout@v4
+        with:
+          #repository: ${{ github.event.pull_request.head.repo.full_name }}
+          ref: ${{ github.event.pull_request.base.sha }}
           fetch-depth: 0
 
-      # HEAD^2~ because PR branch is second parent and we want to skip the last commit
-      - name: Dispatch jobs for commits in PR history
+      # HEAD~ because  we want to skip the last commit (which is built in job above)
+      - name: Create jobs for commits in PR history
+        id: set-matrix
+        run: |
+          echo matrix=$(.ci/matrix-from-commit-log origin/${{github.base_ref}}..${{ github.event.pull_request.head.sha}}~) >> $GITHUB_OUTPUT
+
+  # Run this job for every commit in the PR except HEAD.
+  pr-commit-ci:
+    runs-on: ubuntu-22.04
+    needs: [ generate-matrix ]
+    strategy:
+      matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
+    if: needs.generate-matrix.outputs.matrix != ''
+    steps:
+      - name: Clone the repo
+        uses: actions/checkout@v4
+        with:
+          submodules: recursive
+          #repository: ${{ github.event.pull_request.head.repo.full_name }}
+          ref: ${{ github.event.pull_request.base.sha }}
+
+      - name: Create merge commit
+        env:
+          GIT_AUTHOR_NAME: Bot
+          GIT_AUTHOR_EMAIL: bot@bitbox.swiss
+          GIT_COMMITTER_NAME: Bot
+          GIT_COMMITTER_EMAIL: bot@bitbox.swiss
         run: |
-          for commit in $(git log --format="%H" origin/${{github.base_ref}}..HEAD^2~); do
-            echo ::notice::Dispatching job for $commit
-            curl -L -s \
-              -X POST \
-              -H "Accept: application/vnd.github+json" \
-              -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-              -H "X-GitHub-Api-Version: 2022-11-28" \
-              ${{ github.api_url }}/repos/${{ github.repository }}/actions/workflows/commit-ci.yml/dispatches \
-              -d "{\"ref\":\"${{ github.event.pull_request.head.ref }}\",\"inputs\":{\"sha\":\"$commit\",\"base_ref\":\"${{ github.base_ref}}\"}}"
-          done
+          git fetch origin ${{ matrix.commit }}
+          git merge --no-ff --no-edit ${{ matrix.commit }}
+          echo "merge commit parents:"
+          git log -1 --format="Head %H, Parents %P"
 
       - name: Pull container image
         run: ./.ci/run-container-ci pull