From b0dcb008895eb06455f518a86d087e668b099ef4 Mon Sep 17 00:00:00 2001 From: Nick Otter Date: Thu, 15 Jan 2026 16:03:27 -0700 Subject: [PATCH 1/2] feat: add dynamic Go module discovery with test matrix Add discover-modules job to all Go workflows that dynamically finds go.mod files and outputs module paths as JSON for matrix consumption. Changes: - Add discover-modules job using find + jq to discover Go modules - Update test jobs to use module matrix for parallel execution - Simplify go vet and go test steps using working-directory - Update test report and coverage paths for per-module artifacts - Update go_app_push_main.yml actions to v4/v5 Benefits: - Parallel test execution across modules - Reduced complexity in vet/test steps - Works automatically for any repo with multiple Go modules Co-Authored-By: Claude Opus 4.5 --- .github/workflows/go_app_pull_requests.yml | 44 +++++++++++++------- .github/workflows/go_app_push_main.yml | 48 ++++++++++++++-------- .github/workflows/go_lib_pull_requests.yml | 48 ++++++++++++++-------- .github/workflows/go_lib_push_main.yml | 46 +++++++++++++-------- 4 files changed, 119 insertions(+), 67 deletions(-) diff --git a/.github/workflows/go_app_pull_requests.yml b/.github/workflows/go_app_pull_requests.yml index 299727f..8f966a9 100644 --- a/.github/workflows/go_app_pull_requests.yml +++ b/.github/workflows/go_app_pull_requests.yml @@ -20,6 +20,20 @@ on: env: GOPRIVATE: ${{ inputs.GOPRIVATE }} jobs: + discover-modules: + # + # finds all go modules in the repository + # + runs-on: ubuntu-latest + outputs: + modules: ${{ steps.set-modules.outputs.modules }} + steps: + - uses: actions/checkout@v4 + - name: Find Go modules + id: set-modules + run: | + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + echo "modules=$MODS" >> $GITHUB_OUTPUT commitlint: # # ensures commit messages follow conventional commits @@ -68,20 +82,20 @@ jobs: # # ensure go standards and tests pass # + needs: discover-modules runs-on: ubuntu-latest strategy: matrix: - # List of go versions to test on. - go: ['^1'] + module: ${{ fromJson(needs.discover-modules.outputs.modules) }} steps: # Checkout go code to test. - name: Checkout repo uses: actions/checkout@v4 - # Setup Go for each version in the matrix. + # Setup Go. - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go }} + go-version: "^1" # Use auth to get access to private Git repos for Go code dependencies. - name: Configure git for private modules env: @@ -89,35 +103,35 @@ jobs: GITHUB_USERNAME: ${{ inputs.GH_CI_USER }} run: git config --global url."https://${GITHUB_USERNAME}:${TOKEN}@github.com".insteadOf "https://github.com" - # Go vet every Go module. + # Go vet the module. - name: go vet - run: find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go vet ./..." + working-directory: ${{ matrix.module }} + run: go vet ./... # Install go-junit-report to format test results. - name: Install go-junit-report run: go install github.com/jstemmer/go-junit-report/v2@v2.1.0 - # Run unit test for evet Go module. + # Run unit tests for the module. - name: go test - run: find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go test -coverprofile=coverage.txt --race -v ./..." - | go-junit-report -set-exit-code > junit_report.xml || true + working-directory: ${{ matrix.module }} + run: go test -coverprofile=coverage.txt --race -v ./... 2>&1 | go-junit-report -set-exit-code > junit_report.xml || true - name: Test Report uses: dorny/test-reporter@v1 if: success() || failure() with: - name: Test Report - path: junit_report.xml + name: Test Report (${{ matrix.module }}) + path: ${{ matrix.module }}/junit_report.xml reporter: java-junit - uses: codecov/test-results-action@v1 with: fail_ci_if_error: true # optional (default = false) - files: ./junit_report.xml - name: junit-report + files: ${{ matrix.module }}/junit_report.xml + name: junit-report-${{ strategy.job-index }} token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test coverage results to Codecov uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ matrix.module }}/coverage.txt docker-build: # # ensures the docker image will build without pushing to the registry diff --git a/.github/workflows/go_app_push_main.yml b/.github/workflows/go_app_push_main.yml index a0a69fb..fccc254 100644 --- a/.github/workflows/go_app_push_main.yml +++ b/.github/workflows/go_app_push_main.yml @@ -21,24 +21,38 @@ on: env: GOPRIVATE: ${{ inputs.GOPRIVATE }} jobs: + discover-modules: + # + # finds all go modules in the repository + # + runs-on: ubuntu-latest + outputs: + modules: ${{ steps.set-modules.outputs.modules }} + steps: + - uses: actions/checkout@v4 + - name: Find Go modules + id: set-modules + run: | + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + echo "modules=$MODS" >> $GITHUB_OUTPUT test: # # ensure go standards and tests pass # + needs: discover-modules runs-on: ubuntu-latest strategy: matrix: - # List of go versions to test on. - go: ['^1'] + module: ${{ fromJson(needs.discover-modules.outputs.modules) }} steps: # Checkout go code to test. - name: Checkout repo - uses: actions/checkout@v3 - # Setup Go for each version in the matrix. + uses: actions/checkout@v4 + # Setup Go. - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go }} + go-version: "^1" # Use auth to get access to private Git repos for Go code dependencies. - name: Configure git for private modules env: @@ -46,35 +60,35 @@ jobs: GITHUB_USERNAME: ${{ inputs.GH_CI_USER }} run: git config --global url."https://${GITHUB_USERNAME}:${TOKEN}@github.com".insteadOf "https://github.com" - # Go vet every Go module. + # Go vet the module. - name: go vet - run: find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go vet ./..." + working-directory: ${{ matrix.module }} + run: go vet ./... # Install go-junit-report to format test results. - name: Install go-junit-report run: go install github.com/jstemmer/go-junit-report/v2@v2.1.0 - # Run unit test for evet Go module. + # Run unit tests for the module. - name: go test - run: find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go test -coverprofile=coverage.txt --race -v ./..." - | go-junit-report -set-exit-code > junit_report.xml || true + working-directory: ${{ matrix.module }} + run: go test -coverprofile=coverage.txt --race -v ./... 2>&1 | go-junit-report -set-exit-code > junit_report.xml || true - name: Test Report uses: dorny/test-reporter@v1 if: success() || failure() with: - name: Test Report - path: junit_report.xml + name: Test Report (${{ matrix.module }}) + path: ${{ matrix.module }}/junit_report.xml reporter: java-junit - uses: codecov/test-results-action@v1 with: fail_ci_if_error: true # optional (default = false) - files: ./junit_report.xml - name: junit-report + files: ${{ matrix.module }}/junit_report.xml + name: junit-report-${{ strategy.job-index }} token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test coverage results to Codecov uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ matrix.module }}/coverage.txt release: # # Create a GitHub Release based on conventional commits. diff --git a/.github/workflows/go_lib_pull_requests.yml b/.github/workflows/go_lib_pull_requests.yml index 5ed8c86..ee99f31 100644 --- a/.github/workflows/go_lib_pull_requests.yml +++ b/.github/workflows/go_lib_pull_requests.yml @@ -24,6 +24,20 @@ on: env: GOPRIVATE: ${{ inputs.GOPRIVATE }} jobs: + discover-modules: + # + # finds all go modules in the repository + # + runs-on: ubuntu-latest + outputs: + modules: ${{ steps.set-modules.outputs.modules }} + steps: + - uses: actions/checkout@v4 + - name: Find Go modules + id: set-modules + run: | + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + echo "modules=$MODS" >> $GITHUB_OUTPUT commitlint: # # ensures commit messages follow conventional commits @@ -74,20 +88,20 @@ jobs: # # ensure go standards and tests pass # + needs: discover-modules runs-on: ubuntu-latest strategy: matrix: - # List of go versions to test on. - go: ["^1"] + module: ${{ fromJson(needs.discover-modules.outputs.modules) }} steps: # Checkout go code to test. - name: Checkout repo uses: actions/checkout@v4 - # Setup Go for each version in the matrix. + # Setup Go. - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go }} + go-version: "^1" # Use auth to get access to private Git repos for Go code dependencies. - name: Configure git for private modules env: @@ -96,34 +110,32 @@ jobs: run: git config --global url."https://${GITHUB_USERNAME}:${TOKEN}@github.com".insteadOf "https://github.com" - # Go vet every Go module. + # Go vet the module. - name: go vet - run: - find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go vet ./..." + working-directory: ${{ matrix.module }} + run: go vet ./... # Install go-junit-report to format test results. - name: Install go-junit-report run: go install github.com/jstemmer/go-junit-report/v2@v2.1.0 - # Run unit test for evet Go module. + # Run unit tests for the module. - name: go test - run: - find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go test -coverprofile=coverage.txt --race -v ./..." - | go-junit-report -set-exit-code > junit_report.xml || true + working-directory: ${{ matrix.module }} + run: go test -coverprofile=coverage.txt --race -v ./... 2>&1 | go-junit-report -set-exit-code > junit_report.xml || true - name: Test Report uses: dorny/test-reporter@v1 if: success() || failure() with: - name: Test Report - path: junit_report.xml + name: Test Report (${{ matrix.module }}) + path: ${{ matrix.module }}/junit_report.xml reporter: java-junit - uses: codecov/test-results-action@v1 with: fail_ci_if_error: true # optional (default = false) - files: ./junit_report.xml - name: junit-report + files: ${{ matrix.module }}/junit_report.xml + name: junit-report-${{ strategy.job-index }} token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test coverage results to Codecov uses: codecov/codecov-action@v4 with: - token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file + token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ matrix.module }}/coverage.txt \ No newline at end of file diff --git a/.github/workflows/go_lib_push_main.yml b/.github/workflows/go_lib_push_main.yml index 4112b7d..7a442ad 100644 --- a/.github/workflows/go_lib_push_main.yml +++ b/.github/workflows/go_lib_push_main.yml @@ -21,24 +21,38 @@ on: env: GOPRIVATE: ${{ inputs.GOPRIVATE }} jobs: + discover-modules: + # + # finds all go modules in the repository + # + runs-on: ubuntu-latest + outputs: + modules: ${{ steps.set-modules.outputs.modules }} + steps: + - uses: actions/checkout@v4 + - name: Find Go modules + id: set-modules + run: | + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + echo "modules=$MODS" >> $GITHUB_OUTPUT test: # # ensure go standards and tests pass # + needs: discover-modules runs-on: ubuntu-latest strategy: matrix: - # List of go versions to test on. - go: ["^1"] + module: ${{ fromJson(needs.discover-modules.outputs.modules) }} steps: # Checkout go code to test. - name: Checkout repo uses: actions/checkout@v4 - # Setup Go for each version in the matrix. + # Setup Go. - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go }} + go-version: "^1" # Use auth to get access to private Git repos for Go code dependencies. - name: Configure git for private modules env: @@ -47,37 +61,35 @@ jobs: run: git config --global url."https://${GITHUB_USERNAME}:${TOKEN}@github.com".insteadOf "https://github.com" - # Go vet every Go module. + # Go vet the module. - name: go vet - run: - find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go vet ./..." + working-directory: ${{ matrix.module }} + run: go vet ./... # Install go-junit-report to format test results. - name: Install go-junit-report run: go install github.com/jstemmer/go-junit-report/v2@v2.1.0 - # Run unit test for evet Go module. + # Run unit tests for the module. - name: go test - run: - find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname - | xargs -n1 -I{} bash -c "pushd {}; go test -coverprofile=coverage.txt --race -v ./..." - | go-junit-report -set-exit-code > junit_report.xml || true + working-directory: ${{ matrix.module }} + run: go test -coverprofile=coverage.txt --race -v ./... 2>&1 | go-junit-report -set-exit-code > junit_report.xml || true - name: Test Report uses: dorny/test-reporter@v1 if: success() || failure() with: - name: Test Report - path: junit_report.xml + name: Test Report (${{ matrix.module }}) + path: ${{ matrix.module }}/junit_report.xml reporter: java-junit - uses: codecov/test-results-action@v1 with: fail_ci_if_error: true # optional (default = false) - files: ./junit_report.xml - name: junit-report + files: ${{ matrix.module }}/junit_report.xml + name: junit-report-${{ strategy.job-index }} token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test coverage results to Codecov uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ matrix.module }}/coverage.txt release: # # Create a GitHub Release based on conventional commits. From 354a973ad5ff08e2b80e767f8b82190d63173727 Mon Sep 17 00:00:00 2001 From: Nick Otter Date: Thu, 15 Jan 2026 16:10:37 -0700 Subject: [PATCH 2/2] fix: use compact JSON output for module discovery Use jq -sc (slurp + compact) to output single-line JSON for $GITHUB_OUTPUT compatibility. Multiline JSON was causing "Invalid format" errors in GitHub Actions. Co-Authored-By: Claude Opus 4.5 --- .github/workflows/go_app_pull_requests.yml | 2 +- .github/workflows/go_app_push_main.yml | 2 +- .github/workflows/go_lib_pull_requests.yml | 2 +- .github/workflows/go_lib_push_main.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go_app_pull_requests.yml b/.github/workflows/go_app_pull_requests.yml index 8f966a9..e893bbb 100644 --- a/.github/workflows/go_app_pull_requests.yml +++ b/.github/workflows/go_app_pull_requests.yml @@ -32,7 +32,7 @@ jobs: - name: Find Go modules id: set-modules run: | - MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -sc .) echo "modules=$MODS" >> $GITHUB_OUTPUT commitlint: # diff --git a/.github/workflows/go_app_push_main.yml b/.github/workflows/go_app_push_main.yml index fccc254..0824ef7 100644 --- a/.github/workflows/go_app_push_main.yml +++ b/.github/workflows/go_app_push_main.yml @@ -33,7 +33,7 @@ jobs: - name: Find Go modules id: set-modules run: | - MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -sc .) echo "modules=$MODS" >> $GITHUB_OUTPUT test: # diff --git a/.github/workflows/go_lib_pull_requests.yml b/.github/workflows/go_lib_pull_requests.yml index ee99f31..34c152d 100644 --- a/.github/workflows/go_lib_pull_requests.yml +++ b/.github/workflows/go_lib_pull_requests.yml @@ -36,7 +36,7 @@ jobs: - name: Find Go modules id: set-modules run: | - MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -sc .) echo "modules=$MODS" >> $GITHUB_OUTPUT commitlint: # diff --git a/.github/workflows/go_lib_push_main.yml b/.github/workflows/go_lib_push_main.yml index 7a442ad..b311c70 100644 --- a/.github/workflows/go_lib_push_main.yml +++ b/.github/workflows/go_lib_push_main.yml @@ -33,7 +33,7 @@ jobs: - name: Find Go modules id: set-modules run: | - MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -s .) + MODS=$(find . -name vendor -prune -o -name go.mod -print | xargs -n1 dirname | jq -R . | jq -sc .) echo "modules=$MODS" >> $GITHUB_OUTPUT test: #