| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- name: Update Go Version in "go.mod"
- on:
- schedule:
- - cron: '0 14 * * 1' # Run every Monday at 2 PM UTC
- workflow_dispatch: # Allow manual triggering
- concurrency:
- group: golang-ver-bump
- cancel-in-progress: true
- jobs:
- check-and-update-go:
- name: Check and Update Go Version
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- contents: write
- steps:
- - uses: actions/checkout@v6
- with:
- repository: 'opencost/opencost'
- ref: 'develop'
- fetch-depth: 0
- path: ./opencost
- - name: Setup Go
- uses: actions/setup-go@v6
- with:
- go-version: 'stable'
- - name: Check for existing open PRs
- id: check-existing-prs
- run: |
- # Check if there are any open PRs with the go-version-update label
- EXISTING_PRS=$(gh pr list --label "go-version-update" --state open --json number,title,url)
- if [ "$(echo "$EXISTING_PRS" | jq 'length')" -gt 0 ]; then
- echo "Found existing open PR(s) with go-version-update label:"
- echo "$EXISTING_PRS" | jq -r '.[] | " - #\(.number): \(.title) (\(.url))"'
- echo "skip_update=true" >> $GITHUB_OUTPUT
- else
- echo "No existing open PRs found, proceeding with update check"
- echo "skip_update=false" >> $GITHUB_OUTPUT
- fi
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN}}
- GH_REPO: ${{ github.repository }}
- - name: Get current Go version from go.mod
- id: current-version
- working-directory: ./opencost
- if: steps.check-existing-prs.outputs.skip_update == 'false'
- run: |
- CURRENT_VERSION=$(grep '^go ' go.mod | awk '{print $2}')
- echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
- echo "Current Go version: $CURRENT_VERSION"
- - name: Get latest Go version
- id: latest-version
- working-directory: ./opencost
- if: steps.check-existing-prs.outputs.skip_update == 'false'
- run: |
- # Get the latest Go version from golang.org/dl
- LATEST_VERSION=$(curl -sS https://go.dev/VERSION?m=text | grep -o 'go[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1)
- echo "latest_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
- echo "Latest Go version: $LATEST_VERSION"
- - name: Compare versions
- id: version-check
- working-directory: ./opencost
- if: steps.check-existing-prs.outputs.skip_update == 'false'
- run: |
- CURRENT_VERSION="${{ steps.current-version.outputs.current_version }}"
- LATEST_VERSION="${{ steps.latest-version.outputs.latest_version }}"
- # Remove 'go' prefix for comparison
- CURRENT_NUM=$(echo "$CURRENT_VERSION" | sed 's/^go//')
- LATEST_NUM=$(echo "$LATEST_VERSION" | sed 's/^go//')
- echo "Raw current version: $CURRENT_VERSION"
- echo "Raw latest version: $LATEST_VERSION"
- echo "Current version number: $CURRENT_NUM"
- echo "Latest version number: $LATEST_NUM"
- # Validate that both versions are non-empty and match an expected pattern (e.g., 1.22.1)
- VERSION_REGEX='^[0-9]+\.[0-9]+(\.[0-9]+)?$'
- if ! echo "$CURRENT_NUM" | grep -Eq "$VERSION_REGEX"; then
- echo "Error: CURRENT_VERSION '$CURRENT_VERSION' (normalized: '$CURRENT_NUM') is invalid or empty."
- exit 1
- fi
- if ! echo "$LATEST_NUM" | grep -Eq "$VERSION_REGEX"; then
- echo "Error: LATEST_VERSION '$LATEST_VERSION' (normalized: '$LATEST_NUM') is invalid or empty."
- exit 1
- fi
- if [ "$CURRENT_NUM" = "$LATEST_NUM" ]; then
- echo "Go version is up to date"
- echo "update_needed=false" >> $GITHUB_OUTPUT
- else
- # Use version-aware sorting to determine which version is greater
- HIGHEST_VERSION=$(printf '%s\n' "$CURRENT_NUM" "$LATEST_NUM" | sort -V | tail -n1)
- if [ "$HIGHEST_VERSION" = "$LATEST_NUM" ]; then
- echo "Newer Go version available: $LATEST_VERSION (current: $CURRENT_VERSION)"
- echo "update_needed=true" >> $GITHUB_OUTPUT
- echo "new_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
- else
- echo "Current Go version ($CURRENT_VERSION) is newer than or equal to latest reported version ($LATEST_VERSION); no update needed."
- echo "update_needed=false" >> $GITHUB_OUTPUT
- fi
- fi
- - name: Update go.mod with new Go version
- if: steps.check-existing-prs.outputs.skip_update == 'false' && steps.version-check.outputs.update_needed == 'true'
- working-directory: ./opencost
- run: |
- NEW_VERSION="$(echo '${{ steps.version-check.outputs.new_version }}' | tr -d 'go')"
- echo "Updating all go.mod files under $(pwd) to use Go version: $NEW_VERSION"
- # Recursively update every go.mod we find under the working directory.
- # (Skip vendor directories to avoid accidental edits of vendored content.)
- while IFS= read -r go_mod_file; do
- echo "Updating: $go_mod_file"
- sed -i -E "s/^go[[:space:]].*/go ${NEW_VERSION}/" "$go_mod_file"
- done < <(find . -name go.mod -type f -not -path "*/vendor/*")
-
- - name: Run go mod tidy
- if: steps.check-existing-prs.outputs.skip_update == 'false' && steps.version-check.outputs.update_needed == 'true'
- working-directory: ./opencost
- run: |
- echo "Running go mod tidy for every module found under $(pwd)"
- # Tidy once per module directory (dirname of each go.mod we find).
- # Skip vendor directories to avoid editing vendored content.
- mapfile -t tidy_dirs < <(find . -name go.mod -type f -not -path "*/vendor/*" -exec dirname {} \; | sort -u)
- for d in "${tidy_dirs[@]}"; do
- echo "Tidying: $d"
- (cd "$d" && go mod tidy)
- done
- - name: Check for changes
- id: changes
- if: steps.check-existing-prs.outputs.skip_update == 'false' && steps.version-check.outputs.update_needed == 'true'
- working-directory: ./opencost
- run: |
- if [ -z "$(git status --porcelain)" ]; then
- echo "No changes detected, skipping PR creation"
- echo "skip_pr=true" >> $GITHUB_OUTPUT
- else
- echo "Changes detected, will create PR"
- echo "skip_pr=false" >> $GITHUB_OUTPUT
- # Generate a unique branch name with timestamp
- branch_name="update-go-version-$(date +%Y%m%d-%H%M%S)"
- echo "branch_name=$branch_name" >> $GITHUB_OUTPUT
- fi
- - name: Create Pull Request
- if: steps.check-existing-prs.outputs.skip_update == 'false' && steps.version-check.outputs.update_needed == 'true' && steps.changes.outputs.skip_pr == 'false'
- id: create-pr
- uses: peter-evans/create-pull-request@v8
- with:
- path: ./opencost
- token: ${{ secrets.GITHUB_TOKEN }}
- branch: ${{ steps.changes.outputs.branch_name }}
- title: 'chore: update Go version to ${{ steps.version-check.outputs.new_version }}'
- commit-message: 'chore: update Go version to ${{ steps.version-check.outputs.new_version }}'
- delete-branch: true
- add-paths: |
- go.mod
- go.sum
- **/go.mod
- **/go.sum
- body: |
- Automated PR to update Go version from ${{ steps.current-version.outputs.current_version }} to ${{ steps.version-check.outputs.new_version }}.
-
- This PR was automatically generated after detecting a newer Go version is available.
- base: develop
- labels: automated,go-version-update
-
- - name: Skip message - no update needed
- if: steps.check-existing-prs.outputs.skip_update == 'false' && steps.version-check.outputs.update_needed == 'false'
- run: |
- echo "No Go version update needed. Current version is up to date."
- - name: Skip message - existing PR
- if: steps.check-existing-prs.outputs.skip_update == 'true'
- run: |
- echo "Skipping Go version update because an existing PR with go-version-update label is already open."
|