Regenerate NEAR RPC Client (auto PR, merge & release) #5
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: Regenerate NEAR RPC Client (auto PR, merge & release) | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 0 * * *" # daily at midnight | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| regenerate-merge-release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Avoid infinite loop | |
| - name: Exit if triggered by GitHub Actions bot | |
| if: github.actor == 'github-actions[bot]' | |
| run: | | |
| echo "Triggered by GitHub Actions bot; exiting to avoid loop." | |
| exit 0 | |
| # Checkout repo | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: true | |
| # Setup JDK | |
| - name: Set up JDK 21 | |
| uses: actions/setup-java@v3 | |
| with: | |
| distribution: temurin | |
| java-version: 21 | |
| # Gradlew executable | |
| - name: Grant execute permission for Gradlew | |
| run: chmod +x ./gradlew | |
| # Run Generator (safe) | |
| - name: Run Generator (safe mode) | |
| id: generator | |
| run: | | |
| set +e | |
| ./gradlew :generator:run --args="--openapi-url https://raw.githubusercontent.com/near/nearcore/master/chain/jsonrpc/openapi/openapi.json" --no-daemon | |
| EXIT_CODE=$? | |
| set -e | |
| if [ $EXIT_CODE -ne 0 ]; then | |
| echo "⚠️ OpenAPI generation failed. Skipping regeneration." | |
| echo "pr_required=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Generator completed successfully." | |
| echo "pr_required=true" >> "$GITHUB_OUTPUT" | |
| # Build without tests | |
| - name: Build project (without tests) | |
| run: ./gradlew build -x test --stacktrace --no-daemon | |
| # Prepare branch, commit regenerated sources | |
| - name: Prepare branch, commit regenerated sources | |
| id: commit | |
| env: | |
| PAT_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| git config --local user.email "automation@github.com" | |
| git config --local user.name "GitHub Actions Bot" | |
| SHORT_SHA=${GITHUB_SHA:0:8} | |
| BRANCH="regenerate-openapi-${GITHUB_RUN_NUMBER}-${SHORT_SHA}" | |
| git checkout -b "$BRANCH" | |
| git add . | |
| if git diff --staged --quiet; then | |
| echo "No changes to commit" | |
| echo "pr_required=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| git commit -m "chore: regenerate client from OpenAPI" | |
| git push https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git "$BRANCH" | |
| echo "pr_required=true" >> "$GITHUB_OUTPUT" | |
| echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" | |
| # Auto-create and merge PR | |
| - name: Auto-create and merge PR | |
| if: steps.commit.outputs.pr_required == 'true' | |
| uses: actions/github-script@v6 | |
| with: | |
| github-token: ${{ secrets.PAT_TOKEN }} | |
| script: | | |
| const branch = '${{ steps.commit.outputs.branch }}'; | |
| const title = `chore: regenerate client from OpenAPI (${branch})`; | |
| const body = `This PR regenerates the NEAR RPC client and models from the latest OpenAPI spec.\n\nAutomatically merged after generation.`; | |
| const pr = await github.rest.pulls.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title, | |
| head: branch, | |
| base: "main", | |
| body | |
| }); | |
| await github.rest.pulls.merge({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.data.number, | |
| merge_method: "squash" | |
| }); | |
| # Output when no changes | |
| - name: Output when no changes | |
| if: steps.commit.outputs.pr_required != 'true' | |
| run: echo "No regenerated changes — nothing to create a PR for." | |
| # Sync main after merge | |
| - name: Sync main after merge | |
| if: steps.commit.outputs.pr_required == 'true' | |
| run: | | |
| set -euo pipefail | |
| sleep 10 | |
| git fetch origin main --tags | |
| git checkout main | |
| git reset --hard origin/main | |
| # Determine new tag (SemVer Patch) | |
| - name: Determine new tag version | |
| if: steps.commit.outputs.pr_required == 'true' | |
| id: tag | |
| run: | | |
| set -euo pipefail | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v1.0.0") | |
| IFS='.' read -r MAJOR MINOR PATCH <<<"${LAST_TAG#v}" | |
| MAJOR=${MAJOR:-1} | |
| MINOR=${MINOR:-0} | |
| PATCH=${PATCH:-0} | |
| PATCH=$((PATCH+1)) | |
| NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}" | |
| echo "new_tag=${NEW_TAG}" >> $GITHUB_OUTPUT | |
| echo "Next tag determined: ${NEW_TAG}" | |
| # Create and push tag | |
| - name: Create and push tag | |
| id: create_tag | |
| if: steps.commit.outputs.pr_required == 'true' | |
| env: | |
| PAT_TOKEN: ${{ secrets.PAT_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| NEW_TAG="${{ steps.tag.outputs.new_tag }}" | |
| git fetch --tags | |
| if git rev-parse "refs/tags/${NEW_TAG}" >/dev/null 2>&1; then | |
| echo "Tag ${NEW_TAG} already exists. Skipping." | |
| echo "tag_created=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| git tag -a "${NEW_TAG}" -m "Release ${NEW_TAG} (automated)" | |
| git push "https://x-access-token:${PAT_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "${NEW_TAG}" | |
| echo "tag_created=true" >> $GITHUB_OUTPUT | |
| echo "Created tag ${NEW_TAG}" | |
| # Create GitHub Release | |
| - name: Create GitHub Release | |
| if: steps.create_tag.outputs.tag_created == 'true' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ steps.tag.outputs.new_tag }} | |
| name: "Release ${{ steps.tag.outputs.new_tag }}" | |
| body: | | |
| 🚀 Automated release generated by workflow. | |
| This release was created automatically after merging the regenerated client into main. | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }} |