name: "Update Copilot CLI Version" on: workflow_dispatch: inputs: version: description: "Target github/copilot-cli release version (e.g. 1.0.83-0)" required: true type: string permissions: contents: write pull-requests: write jobs: update: name: "Update Copilot CLI 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. 0.0.420)." exit 1 fi - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 22 - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.22" - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 with: dotnet-version: "10.0.x" # Rust generator runs `cargo fmt` on its output under stable rustfmt; # nightly rustfmt is needed for unstable format options (group_imports, # imports_granularity, reorder_impl_items) pinned in # `rust/.rustfmt.nightly.toml`. See codegen-check.yml for the same step. - name: Install Rust toolchain uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable with: toolchain: "1.94.0" components: rustfmt - name: Install nightly rustfmt uses: dtolnay/rust-toolchain@d1031067263f94b142dd6c0ce24c5eb9d02d52a0 # master with: toolchain: nightly-2026-04-14 components: rustfmt - name: Update the Node.js CLI release pin env: VERSION: ${{ inputs.version }} working-directory: ./nodejs run: | node scripts/set-cli-version.js "$VERSION" npm install --ignore-scripts - name: Refresh nodejs/samples lockfile working-directory: ./nodejs/samples run: npm install - name: Install codegen dependencies working-directory: ./scripts/codegen run: npm ci - name: Run codegen working-directory: ./scripts/codegen run: npm run generate - name: Format generated code run: | cd nodejs && npx prettier --write "src/generated/**/*.ts" cd ../dotnet && dotnet format src/GitHub.Copilot.SDK.csproj cd ../rust && cargo +nightly-2026-04-14 fmt --all -- --config-path .rustfmt.nightly.toml - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: java-version: "25" distribution: "microsoft" - name: Run Java codegen working-directory: ./java run: mvn generate-sources -Pcodegen - name: Create pull request 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" # Fetch the PR branch if it exists remotely (shallow clones may not have it) git fetch origin "$BRANCH" 2>/dev/null || true if git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then # We need to switch to the existing PR branch, but earlier workflow # steps (dependency bumps, codegen) may have left uncommitted changes # in the working tree. We must stash those changes before checkout, # then re-apply them on the PR branch. # # HOWEVER: `git stash` is a no-op when the working tree is clean — # it exits 0 but creates NO refs/stash entry. If we then blindly run # `git stash pop`, it fails with "No stash entries found" and, under # the shell's `set -e` (GitHub Actions default), aborts the entire # step. This happens when the requested version is already current or # earlier steps produced no file changes. # # Fix: only stash/pop when there are actual uncommitted changes. STASHED=false if ! git diff --quiet || ! git diff --cached --quiet; then git stash --include-untracked STASHED=true fi git checkout "$BRANCH" git reset --hard "origin/$BRANCH" # Re-apply the dependency/codegen changes on top of the PR branch, # but only if we actually stashed something above. if [ "$STASHED" = "true" ]; then git stash pop fi else git checkout -b "$BRANCH" fi git add -A if git diff --cached --quiet; then echo "No changes detected; skipping commit and PR creation." exit 0 fi git commit -m "Update Copilot CLI to $VERSION - Updated the shared CLI release pin - Re-ran code generators - Formatted generated code" git push origin "$BRANCH" --force-with-lease PR_BODY=$(cat <<'BODY_EOF' Automated update of the Copilot CLI release to version `PLACEHOLDER_VERSION`. ### Changes - Updated the shared release pin in `nodejs/package.json` - Validated the release assets listed in `SHA256SUMS.txt` - Re-ran all code generators (`scripts/codegen`) - Formatted generated output - Regenerated Java types from the pinned CLI release schemas ### Java Handwritten Code Adaptation Plan If `java-sdk-tests` CI fails on this PR, follow these steps: 1. **Identify failures**: Run `mvn clean`, `mvn verify` from `java/` locally or check the `java-sdk-tests` workflow run logs. 2. **Categorize errors**: - Constructor signature changes (new fields added to generated records) - Enum value additions/renames in generated types - New event types requiring handler registration - Removed or renamed generated types 3. **Fix handwritten source** (`java/sdk/src/main/java/com/github/copilot/sdk/`): - Update call sites passing positional constructor args to include new fields (typically `null` for optional new fields). - Update switch/if-else over enum values to handle new cases. - Register handlers for new event types in `CopilotSession.java` if applicable. 4. **Fix handwritten tests** (`java/sdk/src/test/java/com/github/copilot/sdk/`): - Same constructor/enum fixes as above. - Add new test methods for new functionality if the change adds user-facing API surface. 5. **Validate**: `cd java && mvn clean test-compile jar:jar && mvn verify -Dskip.test.harness=true` 6. **Format**: `cd java && mvn spotless:apply` 7. Push fixes to this PR branch. > To automate this, trigger the `java-adapt-handwritten-code-to-accept-upgrade-changes` agentic workflow instead. ### Next steps When ready, click **Ready for review** to trigger CI checks. > Created by the **Update Copilot CLI Version** workflow. BODY_EOF ) PR_BODY="${PR_BODY//PLACEHOLDER_VERSION/$VERSION}" PR_STATE="$(gh pr view "$BRANCH" --json state --jq '.state' 2>/dev/null || echo "")" if [ "$PR_STATE" = "OPEN" ]; then if [ "$(gh pr view "$BRANCH" --json isDraft --jq '.isDraft')" = "false" ]; then gh pr ready "$BRANCH" --undo echo "Pull request for branch '$BRANCH' already existed and was moved back to draft after updating the branch." else echo "Pull request for branch '$BRANCH' already exists and is already a draft; updated branch only." fi else gh pr create \ --draft \ --title "Update Copilot CLI to $VERSION" \ --body "$PR_BODY" \ --base main \ --head "$BRANCH" fi