diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cc5af4b53..671124b51 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,6 +1,14 @@ name: CI Workflow -on: [pull_request, workflow_dispatch] +on: + pull_request: + # trigger also if labels are set/unsed to allow to ignore the gorelease check + types: [opened, synchronize, reopened, labeled, unlabeled] + workflow_dispatch: + +permissions: + pull-requests: write # required to add comments to the PR + contents: read jobs: main: @@ -13,10 +21,12 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Install Go ${{ matrix.go-version }} uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} + - name: Test run: make test @@ -29,13 +39,87 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Install Go uses: actions/setup-go@v5 with: go-version: 1.25 + - name: Install project tools and dependencies run: make project-tools + - name: Lint run: | make lint scripts/check-sync-tidy.sh + + gorelease-check: + name: Gorelease check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.25 + + - name: Install project tools and dependencies + run: make project-tools + + - name: Create gorelease report + run: make gorelease-report + + # Creates a new comment or updates the existing one to show the report result + - name: Comment PR + uses: actions/github-script@v7 + env: + REPORT_FILE: "gorelease_report.md" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const identifier = ``; + const fs = require('fs'); + + let report = "No output generated."; + if (process.env.REPORT_FILE && fs.existsSync(process.env.REPORT_FILE)) { + report = fs.readFileSync(process.env.REPORT_FILE, 'utf8'); + } + + // Format the comment + const body = `${identifier}\n${report}`; + + // Fetch existing comments on the PR + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + // Look for a comment containing our unique identifier + const existingComment = comments.find(c => c.body.includes(identifier)); + + if (existingComment) { + // Update the existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existingComment.id, + body: body + }); + } else { + // Create a new comment if one doesn't exist + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); + } + + - name: Fail job if gorelease failed + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-gorelease-check') }} + run: make gorelease-check diff --git a/.gitignore b/.gitignore index 14e046c3f..b375916fe 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,7 @@ bin/ *.vscode/ go.work.sum + custom-gcl + +gorelease_report.md diff --git a/Makefile b/Makefile index 53388bb78..91f110443 100644 --- a/Makefile +++ b/Makefile @@ -63,3 +63,9 @@ test-scripts: ## Run tests for scripts test: ## Run all tests @$(MAKE) --no-print-directory test-go skip-non-generated-files=${skip-non-generated-files} service=${service} +gorelease-report: + @$(SCRIPTS_BASE)/gorelease-report.sh + +gorelease-check: + @$(SCRIPTS_BASE)/gorelease-report.sh --strict + diff --git a/scripts/gorelease-report.sh b/scripts/gorelease-report.sh new file mode 100755 index 000000000..ceea2d0a9 --- /dev/null +++ b/scripts/gorelease-report.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +# Default behavior is to NOT fail on gorelease errors. Strict mode is intended for CI pipeline usage. +STRICT_MODE=0 +REPORT_FILE="$(pwd)/gorelease_report.md" +BASE_BRANCH="origin/main" + +# Parse command line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --strict) STRICT_MODE=1 ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +# Initialize/clear the report file +echo -e "# gorelease report\n\ngenerated on $(date)" > "$REPORT_FILE" + +echo "Checking modules under services/ for changes against $BASE_BRANCH..." + +# Iterate over all go.mod files found exactly one level deep in services/ +for mod_file in services/*/go.mod; do + # Skip if no matches were found (handles the case where services/ is empty) + [ -e "$mod_file" ] || continue + + mod_dir=$(dirname "$mod_file") + + # Check if there are any git changes in this specific directory compared to origin/main + # --quiet implies --exit-code (returns 1 if there are differences) + if ! git diff --quiet "$BASE_BRANCH" -- "$mod_dir"; then + echo "Changes detected in $mod_dir. Running gorelease..." + + # Header for this module in the report + echo -e "\n---\n\n### \`gorelease\` report for \`$mod_dir\`\n" >> "$REPORT_FILE" + + # Subshell to avoid directory path issues, though pushd/popd works too + ( + cd "$mod_dir" || exit 1 + + # Disable "exit on error" temporarily so we can capture the output + # even if gorelease finds backwards incompatibilities (which causes exit code 1) + set +e + OUTPUT=$(gorelease 2>&1) + EXIT_CODE=$? + set -e + + # Append findings to the absolute path of the report file + if [ -n "$OUTPUT" ]; then + echo -e "\`\`\`\n$OUTPUT\n\`\`\`" >> "$REPORT_FILE" + else + echo "No API breaking changes or issues detected." >> "$REPORT_FILE" + fi + + echo "" >> "$REPORT_FILE" # Blank line for spacing + + # Handle strict mode exit if gorelease failed (exit code != 0) + if [ $EXIT_CODE -ne 0 ]; then + echo "FAIL: gorelease found issues/failed for $mod_dir (Exit code: $EXIT_CODE)" + + if [ $STRICT_MODE -eq 1 ]; then + echo "Strict mode is enabled. Failing the script immediately." + exit $EXIT_CODE + fi + else + echo "PASS: $mod_dir passed." + fi + ) + + # If the subshell exited with an error (which happens in strict mode), + # propagate that exit code to the main script + SUBSHELL_EXIT=$? + if [ $STRICT_MODE -eq 1 ] && [ $SUBSHELL_EXIT -ne 0 ]; then + exit $SUBSHELL_EXIT + fi + + else + echo "No changes in $mod_dir. Skipping." + fi +done + +echo "" +echo "Done. Aggregate report generated at: $REPORT_FILE" diff --git a/scripts/project.sh b/scripts/project.sh index d427b7ca9..a1cc1688d 100755 --- a/scripts/project.sh +++ b/scripts/project.sh @@ -17,6 +17,9 @@ elif [ "$action" = "tools" ]; then go mod download go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 + + # see https://pkg.go.dev/golang.org/x/exp/cmd/gorelease?tab=versions + go install golang.org/x/exp/cmd/gorelease@v0.0.0-20260718201538-764159d718ef else echo "Invalid action: '$action', please use $0 help for help" fi