feat: refactor pipelines into reusable workflows

sudoforge created

This change refactors the build, test, and benchmarking pipelines to a
`presubmit` and `trunk` parent workflow which invokes other reusable
workflows. This simplifies the deluge of pipelines that are executed,
allowing for better orchestration and reduced noise on failures (only
one email will be sent instead of several).

Closes: michaelmure/git-bug#1198
Change-Id: I52407c39366bb9fbfd8fc1455a4f4a1d94f04897

Change summary

.github/workflows/benchmark.yml       | 46 ------------------
.github/workflows/build-and-test.yml  | 48 +++++++++---------
.github/workflows/codeql-analysis.yml | 57 ----------------------
.github/workflows/codespell.yml       | 23 ---------
.github/workflows/lint.yml            | 74 ++++++++++++++++++++++++++++
.github/workflows/nodejs.yml          | 42 ----------------
.github/workflows/presubmit.yml       | 25 +++++++++
.github/workflows/release.yml         |  2 
.github/workflows/trunk.yml           | 48 ++++++++++++++++++
9 files changed, 171 insertions(+), 194 deletions(-)

Detailed changes

.github/workflows/benchmark.yml 🔗

@@ -1,46 +0,0 @@
-name: Benchmarks
-on:
-  workflow_dispatch:
-  push:
-    branches:
-      - master
-
-concurrency:
-  group: benchmark-${{ github.ref }}
-  cancel-in-progress: true
-
-permissions:
-  # deployments permission to deploy GitHub pages website
-  deployments: write
-  # contents permission to update benchmark contents in gh-pages branch
-  contents: write
-
-jobs:
-  benchmark:
-    name: Performance regression check
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/setup-go@v5
-        with:
-          go-version: 1.22.5
-
-      - uses: actions/checkout@v4
-
-      # Run benchmark with `go test -bench` and stores the output to a file
-      - name: Run benchmark
-        run: go test -v ./... -bench=. -run=xxx -benchmem | tee output.txt
-
-      # Run `github-action-benchmark` action
-      - name: Store benchmark result
-        uses: benchmark-action/github-action-benchmark@v1
-        with:
-          # What benchmark tool the output.txt came from
-          tool: 'go'
-          # Where the output from the benchmark tool is stored
-          output-file-path: output.txt
-          # GitHub API token to make a commit comment
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          # Enable alert commit comment
-          comment-on-alert: true
-          # Push and deploy GitHub pages branch automatically
-          auto-push: true

.github/workflows/go.yml → .github/workflows/build-and-test.yml 🔗

@@ -1,29 +1,17 @@
-name: Go build and test
+name: build-and-test
 
 on:
-  push:
-    branches: [ master ]
-  pull_request:
-    branches: [ master ]
-  workflow_dispatch:
-
-concurrency:
-  group: go-${{ github.ref }}
-  cancel-in-progress: true
+  workflow_call:
 
 jobs:
-  build:
-
+  with-go:
     strategy:
       matrix:
         go-version: [1.22.5]
         platform: [ubuntu-latest, macos-latest, windows-latest]
-
     runs-on: ${{ matrix.platform }}
-
     steps:
-
-      - name: Set up Go ${{ matrix.node-version }}
+      - name: Set up Go ${{ matrix.go-version }}
         uses: actions/setup-go@v5
         with:
           go-version: ${{ matrix.go-version }}
@@ -43,17 +31,29 @@ jobs:
           GITHUB_TOKEN_PUBLIC: ${{ secrets._GITHUB_TOKEN_PUBLIC }}
           GITLAB_API_TOKEN: ${{ secrets.GITLAB_API_TOKEN }}
           GITLAB_PROJECT_ID: ${{ secrets.GITLAB_PROJECT_ID }}
-  
-  lint:
+
+  with-node:
     runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        node-version: [12.x, 14.x, 16.x]
+    defaults:
+      run:
+        working-directory: webui
     steps:
-      - name: Install Go
-        uses: actions/setup-go@v5
+      - name: Setup Node.js ${{ matrix.node-version }}
+        uses: actions/setup-node@v4
         with:
-          go-version: 1.19.4
+          node-version: ${{ matrix.node-version }}
 
-      - name: Checkout code
+      - name: Check out code
         uses: actions/checkout@v4
 
-      - name: Check Code Formatting
-        run: find . -name "*.go" | while read line; do [ -z "$(gofmt -d "$line" | head)" ] || exit 1; done
+      - name: Install
+        run: make install
+
+      - name: Build
+        run: make build
+
+      - name: Test
+        run: make test

.github/workflows/codeql-analysis.yml 🔗

@@ -1,57 +0,0 @@
-name: "Code scanning - action"
-
-on:
-  push:
-    branches: [master, ]
-  pull_request:
-    # The branches below must be a subset of the branches above
-    branches: [master]
-  schedule:
-    - cron: '0 12 * * 6'
-
-concurrency:
-  group: codeql-${{ github.ref }}
-  cancel-in-progress: true
-
-jobs:
-  CodeQL-Build:
-
-    runs-on: ubuntu-latest
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v4
-      with:
-        # We must fetch at least the immediate parents so that if this is
-        # a pull request then we can checkout the head.
-        fetch-depth: 2
-
-    # If this run was triggered by a pull request event, then checkout
-    # the head of the pull request instead of the merge commit.
-    - run: git checkout HEAD^2
-      if: ${{ github.event_name == 'pull_request' }}
-
-    # Initializes the CodeQL tools for scanning.
-    - name: Initialize CodeQL
-      uses: github/codeql-action/init@v3
-      with:
-        languages: go, javascript
-
-    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
-    # If this step fails, then you should remove it and run the build manually (see below)
-    - name: Autobuild
-      uses: github/codeql-action/autobuild@v3
-
-    # â„šī¸ Command-line programs to run using the OS shell.
-    # 📚 https://git.io/JvXDl
-
-    # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines
-    #    and modify them (or add more) to build your code if your project
-    #    uses a compiled language
-
-    #- run: |
-    #   make bootstrap
-    #   make release
-
-    - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v3

.github/workflows/codespell.yml 🔗

@@ -1,23 +0,0 @@
----
-name: Codespell
-
-on:
-  push:
-    branches: [master]
-  pull_request:
-    branches: [master]
-
-concurrency:
-  group: codespell-${{ github.ref }}
-  cancel-in-progress: true
-
-jobs:
-  codespell:
-    name: Check for spelling errors
-    runs-on: ubuntu-latest
-
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v4
-      - name: Codespell
-        uses: codespell-project/actions-codespell@v2

.github/workflows/lint.yml 🔗

@@ -0,0 +1,74 @@
+name: lint
+
+on:
+  workflow_call:
+
+jobs:
+  filter:
+    name: filter
+    runs-on: ubuntu-latest
+    outputs:
+      golang: ${{ steps.filter.outputs.golang }}
+      golang_files: ${{ steps.filter.outputs.golang_files }}
+    steps:
+      - uses: actions/checkout@v4
+      - uses: dorny/paths-filter@v3
+        id: filter
+        with:
+          list-files: shell
+          filters: |
+            golang:
+              - added|modified: '**/*.go'
+              - added|modified: '/go.sum'
+              - added|modified: '/go.mod'
+
+  codeql:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+      with:
+        # We must fetch at least the immediate parents so that if this is
+        # a pull request then we can checkout the head.
+        fetch-depth: 2
+
+    - run: git checkout HEAD^2
+      if: ${{ github.event_name == 'pull_request' }}
+
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v3
+      with:
+        languages: go, javascript
+
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v3
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v3
+
+  spelling:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Check spelling
+        uses: codespell-project/actions-codespell@v2
+
+  go:
+    runs-on: ubuntu-latest
+    needs:
+      - filter
+    if: needs.filter.outputs.golang == 'true'
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: 1.22.5
+
+      - name: Checkout code
+        uses: actions/checkout@v4
+
+      - name: Check Code Formatting
+        run: |
+          test -z "$(gofmt -d ${{ needs.filter.outputs.golang_files }})" || exit 1

.github/workflows/nodejs.yml 🔗

@@ -1,42 +0,0 @@
-name: Node.js build and test
-
-on:
-  push:
-    branches: [ master ]
-  pull_request:
-    branches: [ master ]
-  workflow_dispatch:
-
-concurrency:
-  group: nodejs-${{ github.ref }}
-  cancel-in-progress: true
-
-defaults:
-  run:
-    working-directory: webui
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-
-    strategy:
-      matrix:
-        node-version: [12.x, 14.x, 16.x]
-
-    steps:
-      - name: Setup Node.js ${{ matrix.node-version }}
-        uses: actions/setup-node@v4
-        with:
-          node-version: ${{ matrix.node-version }}
-
-      - name: Check out code
-        uses: actions/checkout@v4
-
-      - name: Install
-        run: make install
-
-      - name: Build
-        run: make build
-
-      - name: Test
-        run: make test

.github/workflows/presubmit.yml 🔗

@@ -0,0 +1,25 @@
+# //.github/workflows:presubmit.yml
+#
+# This file exists to define the steps executed for a push to each tree matching
+# the pattern `refs/heads/*`, excluding the default ref. For configuring the
+# steps that occur after a push to the trunk branch, see
+# `//.github/workflows:trunk.yml`.
+---
+name: presubmit
+
+on:
+  push:
+    branches-ignore:
+      - master
+
+concurrency:
+  group: ${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  lint:
+    uses: ./.github/workflows/lint.yml
+
+  build-and-test:
+    uses: ./.github/workflows/build-and-test.yml
+    secrets: inherit

.github/workflows/release.yml 🔗

@@ -1,7 +1,6 @@
 name: Build release binaries
 
 on:
-  workflow_dispatch:
   push:
     tags:
       - "v*"
@@ -13,7 +12,6 @@ concurrency:
 jobs:
   build-release:
     runs-on: "ubuntu-latest"
-
     steps:
       - name: Set up Go
         uses: actions/setup-go@v5

.github/workflows/trunk.yml 🔗

@@ -0,0 +1,48 @@
+# //.github/workflows:trunk.yml
+#
+# This file exists to define the steps executed for a push to the default tree.
+# For configuring the steps that occur after a push to all other branches under
+# the refs/heads namespace, see `//.github/workflows:presubmit.yml`.
+---
+name: trunk
+
+on:
+  push:
+    branches:
+      - master
+
+concurrency:
+  group: ${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  lint:
+    uses: ./.github/workflows/lint.yml
+
+  build-and-test:
+    uses: ./.github/workflows/build-and-test.yml
+    secrets: inherit
+
+  benchmark:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+      deployments: write
+    steps:
+      - uses: actions/setup-go@v5
+        with:
+          go-version: 1.22.5
+
+      - uses: actions/checkout@v4
+
+      - name: Run benchmark
+        run: go test -v ./... -bench=. -run=xxx -benchmem | tee output.txt
+
+      - name: Store benchmark result
+        uses: benchmark-action/github-action-benchmark@v1
+        with:
+          tool: 'go'
+          output-file-path: output.txt
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          comment-on-alert: true
+          auto-push: true