Auto Bump Module Dependencies #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Auto Bump Module Dependencies | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| coreVersion: | |
| description: 'Core modular version (e.g. v1.9.0)' | |
| required: true | |
| type: string | |
| workflow_call: | |
| inputs: | |
| coreVersion: | |
| required: true | |
| type: string | |
| secrets: | |
| GH_TOKEN: | |
| required: true | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| actions: read | |
| checks: write | |
| jobs: | |
| bump: | |
| runs-on: ubuntu-latest | |
| env: | |
| GOTOOLCHAIN: auto | |
| CGO_ENABLED: 0 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Remove go.work files | |
| run: | | |
| git rm -f go.work || true | |
| git rm -f go.work.sum || true | |
| rm -f go.work go.work.sum || true | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '^1.25' | |
| check-latest: true | |
| - name: Determine version | |
| id: ver | |
| run: | | |
| V='${{ inputs.coreVersion || github.event.inputs.coreVersion }}' | |
| [[ $V == v* ]] || V="v$V" | |
| echo "Using core version $V" | |
| echo "core_version=$V" >> $GITHUB_OUTPUT | |
| - name: Update module go.mod files | |
| run: | | |
| set -euo pipefail | |
| CORE=${{ steps.ver.outputs.core_version }} | |
| UPDATED=0 | |
| for mod in modules/*/go.mod; do | |
| [ -f "$mod" ] || continue | |
| dir=$(dirname "$mod") | |
| # If the require line exists with a version different from CORE, update via go mod edit (portable, avoids sed incompat) | |
| if grep -q "github.com/GoCodeAlone/modular v" "$mod" && ! grep -q "github.com/GoCodeAlone/modular ${CORE}" "$mod"; then | |
| (cd "$dir" && go mod edit -require=github.com/GoCodeAlone/modular@${CORE}) | |
| UPDATED=1 | |
| fi | |
| # Drop any replace directive pointing to local modular path to avoid accidental pinning | |
| (cd "$dir" && go mod edit -dropreplace=github.com/GoCodeAlone/modular 2>/dev/null || true) | |
| done | |
| if [ "$UPDATED" = 0 ]; then | |
| echo "No module files needed updating" | |
| else | |
| echo "Module go.mod files updated to ${CORE}" | |
| fi | |
| - name: Go mod tidy each module | |
| run: | | |
| set -euo pipefail | |
| for dir in modules/*/; do | |
| [ -f "$dir/go.mod" ] || continue | |
| echo "Tidying $dir" | |
| (cd "$dir" && go mod tidy) | |
| done | |
| - name: Go mod tidy each example | |
| run: | | |
| set -euo pipefail | |
| for dir in examples/*/; do | |
| [ -f "$dir/go.mod" ] || continue | |
| echo "Tidying $dir" | |
| (cd "$dir" && go mod tidy) | |
| done | |
| - name: Go mod tidy root (defensive) | |
| run: | | |
| set -euo pipefail | |
| if [ -f go.mod ]; then | |
| echo "Tidying root module" | |
| go mod tidy | |
| fi | |
| - name: Go mod tidy modcli | |
| run: | | |
| set -euo pipefail | |
| if [ -f cmd/modcli/go.mod ]; then | |
| echo "Tidying cmd/modcli" | |
| (cd cmd/modcli && go mod tidy) | |
| fi | |
| - name: Update documentation version references | |
| run: | | |
| set -euo pipefail | |
| CORE=${{ steps.ver.outputs.core_version }} | |
| OLD=$(git grep -h -o 'github.com/GoCodeAlone/modular v[0-9]\+\.[0-9]\+\.[0-9]\+' -- '*.md' | grep -v $CORE | head -n1 | awk '{print $1}' || true) | |
| # Replace any explicit old version with current in markdown examples | |
| if [ -n "$OLD" ]; then | |
| find . -name '*.md' -print0 | xargs -0 sed -i "" -E "s#github.com/GoCodeAlone/modular v[0-9]+\.[0-9]+\.[0-9]+#github.com/GoCodeAlone/modular ${CORE}#g" || find . -name '*.md' -print0 | xargs -0 sed -i -E "s#github.com/GoCodeAlone/modular v[0-9]+\.[0-9]+\.[0-9]+#github.com/GoCodeAlone/modular ${CORE}#g" | |
| fi | |
| - name: Create PR | |
| id: pr | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| CORE=${{ steps.ver.outputs.core_version }} | |
| BRANCH=auto/bump-modules-${CORE} | |
| git config user.name 'github-actions' | |
| git config user.email 'github-actions@users.noreply.github.com' | |
| # Stage and commit changes first on detached HEAD (checkout provided by actions/checkout) | |
| if git diff --quiet; then | |
| echo "No changes to commit" | |
| echo "created=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| git add . | |
| git commit -m "chore: bump module dependencies to ${CORE}" | |
| # Create or reset branch name to current commit (safe overwrite of existing remote branch) | |
| git branch -f "$BRANCH" | |
| git checkout -B "$BRANCH" | |
| echo "Pushing branch $BRANCH (force-with-lease)" | |
| if ! git push --force-with-lease origin "$BRANCH"; then | |
| git push --force origin "$BRANCH" | |
| fi | |
| PR_URL=$(gh pr view "$BRANCH" --json url --jq .url 2>/dev/null || gh pr create --title "chore: bump module dependencies to ${CORE}" --body "Automated update of module go.mod files and docs to ${CORE}." --head "$BRANCH" --base main --draft=false) | |
| echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT | |
| echo "created=true" >> $GITHUB_OUTPUT | |
| - name: Run full tests (core + modules + examples + CLI) | |
| if: steps.pr.outputs.created == 'true' | |
| run: | | |
| set -euo pipefail | |
| echo "Enabling CGO for race builds" | |
| export CGO_ENABLED=1 | |
| if command -v golangci-lint >/dev/null 2>&1; then golangci-lint run; fi | |
| go test ./... -count=1 -race -timeout=15m | |
| for module in modules/*/; do | |
| if [ -f "$module/go.mod" ]; then | |
| echo "Testing $module"; (cd "$module" && go test ./... -count=1 -race -timeout=15m) | |
| fi | |
| done | |
| for example in examples/*/; do | |
| if [ -f "$example/go.mod" ]; then | |
| echo "Testing $example"; (cd "$example" && go test ./... -count=1 -race -timeout=15m) | |
| fi | |
| done | |
| (cd cmd/modcli && go test ./... -count=1 -race -timeout=15m) | |
| - name: Merge PR | |
| if: steps.pr.outputs.created == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| PR=${{ steps.pr.outputs.pr_url }} | |
| [ -z "$PR" ] && { echo 'No PR URL'; exit 0; } | |
| # Try to enable auto-merge first; if policies block it, attempt an admin squash merge; otherwise leave PR open | |
| if ! gh pr merge "$PR" --squash --delete-branch --auto; then | |
| gh pr merge "$PR" --squash --delete-branch --admin || echo "Merge deferred: branch policies prevent automatic merge" | |
| fi |