Update @github/copilot Dependency #3
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: "Update @github/copilot Dependency" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Target version of @github/copilot (e.g. 1.0.24)' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| actions: write | |
| jobs: | |
| update: | |
| name: "Update @github/copilot to ${{ inputs.version }}" | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Validate version input | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| run: | | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$ ]]; then | |
| echo "::error::Invalid version format '$VERSION'. Expected semver (e.g. 1.0.24)." | |
| exit 1 | |
| fi | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 | |
| with: | |
| node-version: 22 | |
| - name: Update @github/copilot in scripts/codegen | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| working-directory: ./scripts/codegen | |
| # npm install updates package.json and package-lock.json to the new | |
| # version; npm ci (below) then does a clean, reproducible install from | |
| # the updated lock file. Both steps are required: npm install alone | |
| # leaves leftover packages, while npm ci alone cannot change the pinned | |
| # version in the lock file. | |
| run: npm install "@github/copilot@$VERSION" | |
| - name: Install codegen dependencies | |
| working-directory: ./scripts/codegen | |
| run: npm ci | |
| - name: Run codegen | |
| working-directory: ./scripts/codegen | |
| run: npm run generate | |
| - uses: ./.github/actions/setup-copilot | |
| - name: Verify generated code against schema | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} | |
| run: | | |
| cat > /tmp/verify-codegen-prompt.txt << 'PROMPT_EOF' | |
| You are running inside the copilot-sdk-java repository. | |
| The code generator has just run and produced Java source files under | |
| src/generated/java/com/github/copilot/sdk/generated/rpc/. | |
| Your task is to spot-check the generated API classes against the source | |
| JSON schema to verify the generator produced correct output. | |
| **Critical constraint: Do NOT modify any files. This is a read-only | |
| verification. Use only read/inspect operations.** | |
| **Steps:** | |
| 1. Read the API schema at: | |
| scripts/codegen/node_modules/@github/copilot/schemas/api.schema.json | |
| 2. Pick these 3 generated API classes to verify: | |
| - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java | |
| - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java | |
| - src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java | |
| 3. For each class, verify: | |
| - Every RPC method in the schema's corresponding namespace has a | |
| matching Java method in the generated class | |
| - Parameter record fields match the JSON schema property names | |
| - Java types are consistent with JSON schema types (String for | |
| "string", Integer/int for "integer", Boolean/boolean for | |
| "boolean", List for "array", Map or a generated class for | |
| "object", etc.) | |
| - No extra methods exist in the Java class that are not in the | |
| schema | |
| 4. Print a summary table of what was checked and the result for each | |
| method. | |
| 5. If ANY mismatch is found, print the details and exit with a | |
| non-zero code. | |
| If all checks pass, print "Schema verification passed" and exit 0. | |
| PROMPT_EOF | |
| copilot --yolo --prompt "$(cat /tmp/verify-codegen-prompt.txt)" | |
| # --- Commit, create PR, then run mvn verify --- | |
| # The PR must exist before triggering the agentic fix workflow, which | |
| # uses push-to-pull-request-branch safe-output to push fixes. | |
| - name: Commit and push changes | |
| id: commit-changes | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ inputs.version }} | |
| run: | | |
| BRANCH="update-copilot-$VERSION" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| if git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then | |
| git checkout "$BRANCH" | |
| git reset --hard HEAD | |
| else | |
| git checkout -b "$BRANCH" | |
| fi | |
| git add -A | |
| if git diff --cached --quiet; then | |
| echo "No changes detected; skipping commit and PR creation." | |
| echo "has_changes=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| git commit -m "Update @github/copilot to $VERSION | |
| - Updated @github/copilot in scripts/codegen | |
| - Re-ran Java code generator" | |
| git push origin "$BRANCH" --force-with-lease | |
| echo "has_changes=true" >> "$GITHUB_OUTPUT" | |
| echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" | |
| - name: Create pull request | |
| id: create-pr | |
| if: steps.commit-changes.outputs.has_changes == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ inputs.version }} | |
| BRANCH: ${{ steps.commit-changes.outputs.branch }} | |
| run: | | |
| if gh pr view "$BRANCH" >/dev/null 2>&1; then | |
| echo "Pull request for branch '$BRANCH' already exists; updated branch only." | |
| PR_NUMBER=$(gh pr view "$BRANCH" --json number --jq .number) | |
| else | |
| PR_NUMBER=$(gh pr create \ | |
| --title "Update @github/copilot to $VERSION" \ | |
| --body "Automated update of \`@github/copilot\` to version \`$VERSION\`. | |
| ### Changes | |
| - Updated \`@github/copilot\` in \`scripts/codegen/package.json\` | |
| - Re-ran Java code generator (\`scripts/codegen\`) | |
| > Created by the **Update @github/copilot Dependency** workflow." \ | |
| --base main \ | |
| --head "$BRANCH" \ | |
| | grep -oE '[0-9]+$' || gh pr view "$BRANCH" --json number --jq .number) | |
| fi | |
| echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" | |
| # --- Build verification --- | |
| - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 | |
| if: steps.commit-changes.outputs.has_changes == 'true' | |
| with: | |
| java-version: "17" | |
| distribution: "microsoft" | |
| cache: "maven" | |
| - name: Run mvn verify | |
| id: mvn-verify | |
| if: steps.commit-changes.outputs.has_changes == 'true' | |
| continue-on-error: true | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} | |
| run: | | |
| set -o pipefail | |
| mvn verify 2>&1 | tee /tmp/mvn-verify-output.txt | |
| echo "exit_code=$?" >> "$GITHUB_OUTPUT" | |
| - name: Capture error summary | |
| id: error-summary | |
| if: steps.mvn-verify.outcome == 'failure' | |
| run: | | |
| # Extract the last 80 lines as error summary (enough context for the agent) | |
| SUMMARY=$(tail -80 /tmp/mvn-verify-output.txt) | |
| # Write to file to avoid shell escaping issues with multiline strings | |
| echo "$SUMMARY" > /tmp/error-summary.txt | |
| echo "has_errors=true" >> "$GITHUB_OUTPUT" | |
| # --- Agentic fix on failure --- | |
| - name: Trigger agentic fix workflow | |
| id: trigger-fix | |
| if: steps.error-summary.outputs.has_errors == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| BRANCH: ${{ steps.commit-changes.outputs.branch }} | |
| PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} | |
| run: | | |
| ERROR_SUMMARY=$(cat /tmp/error-summary.txt) | |
| gh workflow run codegen-agentic-fix.lock.yml \ | |
| -f branch="$BRANCH" \ | |
| -f pr_number="$PR_NUMBER" \ | |
| -f error_summary="$ERROR_SUMMARY" | |
| echo "Triggered codegen-agentic-fix workflow on branch $BRANCH" | |
| - name: Wait for agentic fix to complete | |
| if: steps.trigger-fix.outcome == 'success' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| BRANCH: ${{ steps.commit-changes.outputs.branch }} | |
| run: | | |
| echo "Waiting for agentic fix workflow to start..." | |
| sleep 30 | |
| for i in $(seq 1 60); do | |
| RUN_ID=$(gh run list \ | |
| --workflow=codegen-agentic-fix.lock.yml \ | |
| --branch="$BRANCH" \ | |
| --limit=1 \ | |
| --json databaseId,status \ | |
| --jq '.[0].databaseId') | |
| STATUS=$(gh run list \ | |
| --workflow=codegen-agentic-fix.lock.yml \ | |
| --branch="$BRANCH" \ | |
| --limit=1 \ | |
| --json databaseId,status \ | |
| --jq '.[0].status') | |
| if [ "$STATUS" = "completed" ]; then | |
| echo "Agentic fix workflow run $RUN_ID completed." | |
| CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq .conclusion) | |
| echo "Conclusion: $CONCLUSION" | |
| break | |
| fi | |
| echo "Run $RUN_ID status: $STATUS (attempt $i/60)" | |
| sleep 30 | |
| done | |
| if [ "$STATUS" != "completed" ]; then | |
| echo "::warning::Agentic fix workflow did not complete within 30 minutes." | |
| fi | |
| - name: Fetch latest changes after agentic fix | |
| if: steps.trigger-fix.outcome == 'success' | |
| env: | |
| BRANCH: ${{ steps.commit-changes.outputs.branch }} | |
| run: | | |
| git fetch origin "$BRANCH" | |
| git reset --hard "origin/$BRANCH" | |
| - name: Final mvn verify after agentic fix | |
| if: steps.trigger-fix.outcome == 'success' | |
| env: | |
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} | |
| run: mvn verify |