diff --git a/.github/actions/setup-copilot/action.yml b/.github/actions/setup-copilot/action.yml index dcc99b8a7..ec15f0d60 100644 --- a/.github/actions/setup-copilot/action.yml +++ b/.github/actions/setup-copilot/action.yml @@ -4,15 +4,36 @@ outputs: cli-path: description: "Path to the Copilot CLI executable" value: ${{ steps.cli-path.outputs.path }} + cli-version: + description: "Pinned @github/copilot version installed (read from pom.xml)" + value: ${{ steps.cli-version.outputs.version }} runs: using: "composite" steps: - - uses: actions/setup-node@v6 + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v6 with: node-version: 22 - - name: Install Copilot CLI - run: npm install -g @github/copilot + - name: Read pinned @github/copilot version from pom.xml + id: cli-version shell: bash + # The version is the SINGLE SOURCE OF TRUTH for the Copilot CLI version + # used across all CI paths. It is kept in sync with the reference + # implementation pinned in .lastmerge by + # .github/scripts/reference-impl-sync/sync-cli-version-from-reference-impl.sh. + run: | + PROP="readonly-copilot-sdk-ref-impl-version-from-lastmerge-file-updated-by-weekly-reference-impl-sync" + VERSION=$(sed -n "s|.*<${PROP}>\(.*\).*|\1|p" pom.xml | head -n 1 | tr -d '[:space:]') + if [[ -z "$VERSION" || "$VERSION" == "PRIMER_TO_REPLACE" ]]; then + echo "::error::Could not read pinned @github/copilot version from pom.xml property <${PROP}>" >&2 + exit 1 + fi + echo "Pinned @github/copilot version: $VERSION" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + - name: Install Copilot CLI (pinned to pom.xml version) + shell: bash + env: + CLI_VERSION: ${{ steps.cli-version.outputs.version }} + run: npm install -g "@github/copilot@${CLI_VERSION}" - name: Set CLI path id: cli-path run: echo "path=$(which copilot)" >> $GITHUB_OUTPUT diff --git a/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh b/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh index 480d43bc0..0801f2548 100755 --- a/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh +++ b/.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh @@ -5,8 +5,10 @@ # Finalises a reference implementation merge: # 1. Runs format + test + build (via format-and-test.sh) # 2. Updates .lastmerge to reference implementation HEAD -# 3. Commits the .lastmerge update -# 4. Pushes the branch to origin +# 3. Syncs the @github/copilot version property in pom.xml from the +# cloned reference implementation's nodejs/package.json +# 4. Commits the .lastmerge + pom.xml updates +# 5. Pushes the branch to origin # # Usage: ./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh # ./.github/scripts/reference-impl-sync/merge-reference-impl-finish.sh --skip-tests @@ -48,8 +50,14 @@ echo "▸ Updating .lastmerge…" NEW_COMMIT=$(cd "$REFERENCE_IMPL_DIR" && git rev-parse origin/main) echo "$NEW_COMMIT" > "$ROOT_DIR/.lastmerge" -git add .lastmerge -git commit -m "Update .lastmerge to $NEW_COMMIT" +# ── 2b. Sync pom.xml @github/copilot version ───────────────── +# Keeps the canonical CLI version in pom.xml aligned with what the +# reference implementation pinned in .lastmerge depends on. +echo "▸ Syncing @github/copilot version in pom.xml from reference implementation…" +"$ROOT_DIR/.github/scripts/reference-impl-sync/sync-cli-version-from-reference-impl.sh" "$REFERENCE_IMPL_DIR" + +git add .lastmerge pom.xml +git commit -m "Update .lastmerge to $NEW_COMMIT and sync pom.xml CLI version" # ── 3. Push branch ─────────────────────────────────────────── echo "▸ Pushing branch $BRANCH_NAME to origin…" diff --git a/.github/scripts/reference-impl-sync/sync-cli-version-from-reference-impl.sh b/.github/scripts/reference-impl-sync/sync-cli-version-from-reference-impl.sh new file mode 100755 index 000000000..5cdbd78e1 --- /dev/null +++ b/.github/scripts/reference-impl-sync/sync-cli-version-from-reference-impl.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────── +# sync-cli-version-from-reference-impl.sh +# +# Reads the @github/copilot version specifier from the cloned +# reference implementation's nodejs/package.json, and updates the +# corresponding property in pom.xml: +# +# +# +# This keeps the canonical Copilot CLI version (declared in pom.xml) +# in sync with whatever the reference implementation pinned in +# .lastmerge depends on. All workflows that install the Copilot CLI +# (build-test.yml — implicitly via cloned SDK, run-smoke-test.yml and +# update-copilot-dependency.yml — via the setup-copilot action) read +# this single property so every CI path uses the same CLI version. +# +# Usage: +# ./sync-cli-version-from-reference-impl.sh +# +# Or, when invoked from merge-reference-impl-finish.sh, sources +# REFERENCE_IMPL_DIR from the .merge-env file. +# ────────────────────────────────────────────────────────────── +set -euo pipefail + +# Locate the repo root by walking up from this script until we find a pom.xml. +# This is resilient to the script being moved to a different depth under +# .github/scripts/ in the future. +find_repo_root() { + local dir + dir="$(cd "$(dirname "$0")" && pwd)" + while [[ "$dir" != "/" ]]; do + if [[ -f "$dir/pom.xml" ]]; then + echo "$dir" + return 0 + fi + dir="$(dirname "$dir")" + done + echo "❌ Could not locate repo root (no pom.xml found above $(dirname "$0"))" >&2 + return 1 +} +ROOT_DIR="$(find_repo_root)" + +REFERENCE_IMPL_DIR="${1:-${REFERENCE_IMPL_DIR:-}}" +if [[ -z "$REFERENCE_IMPL_DIR" ]]; then + echo "❌ Usage: $0 " >&2 + echo " or set REFERENCE_IMPL_DIR in the environment." >&2 + exit 1 +fi + +PKG_JSON="$REFERENCE_IMPL_DIR/nodejs/package.json" +if [[ ! -f "$PKG_JSON" ]]; then + echo "❌ Cannot find $PKG_JSON" >&2 + exit 1 +fi + +# node is always available since the reference implementation uses npm. +CLI_VERSION=$(node -e \ + "const fs=require('fs');const p=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));const v=(p.dependencies&&p.dependencies['@github/copilot'])||(p.devDependencies&&p.devDependencies['@github/copilot']);process.stdout.write(v||'');" \ + "$PKG_JSON") + +if [[ -z "$CLI_VERSION" ]]; then + echo "❌ Could not extract @github/copilot version from $PKG_JSON" >&2 + exit 1 +fi + +POM="$ROOT_DIR/pom.xml" +PROP="readonly-copilot-sdk-ref-impl-version-from-lastmerge-file-updated-by-weekly-reference-impl-sync" + +if ! grep -q "<${PROP}>" "$POM"; then + echo "❌ Property <${PROP}> not found in $POM" >&2 + exit 1 +fi + +# Use a portable sed invocation (works on both BSD/macOS and GNU/Linux). +TMP="$(mktemp)" +sed -E "s|<${PROP}>[^<]*|<${PROP}>${CLI_VERSION}|" "$POM" > "$TMP" +mv "$TMP" "$POM" + +echo "▸ Updated pom.xml: <${PROP}> = ${CLI_VERSION}" diff --git a/.gitignore b/.gitignore index 35ea546f0..654d3278f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ changebundle.txt* .settings scripts/codegen/node_modules/ *~ +*.sln diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f86976c01..38f2def77 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,7 +38,9 @@ If you have ideas for entirely new features, please post an issue or start a dis 1. Push to your fork and [submit a pull request][pr] 1. Pat yourself on the back and wait for your pull request to be reviewed and merged. -### Running tests and linters +### Running locally, including tests and linters + +The POM has logic to ensure a known correct installation of Copilot CLI is used when executing the tests. If you want to test against a different installation of Copilot CLI, set the value of the `copilot.cli.path` maven property to the fully qualified path to the Copilot CLI. ```bash # Build and run all tests @@ -54,6 +56,22 @@ mvn spotless:apply mvn spotless:check ``` +## Running the known correct Copilot CLI installation + +### POSIX + +```bash +export COPILOT_CLI_PATH="$(find "$PWD/target" -type f -path '*/nodejs/node_modules/@github/copilot/index.js' | head -n 1)" +node ${COPILOT_CLI_PATH} +``` + +### PowerShell + +```PowerShell +$env:COPILOT_CLI_PATH = (Get-ChildItem -Path "$PWD\target" -Recurse -Filter 'index.js' -File | Where-Object { $_.FullName -match '[\\/]nodejs[\\/]node_modules[\\/]@github[\\/]copilot[\\/]index\.js$' } | Select-Object -First 1 -ExpandProperty FullName) +node $env:COPILOT_CLI_PATH +``` + Here are a few things you can do that will increase the likelihood of your pull request being accepted: - Write tests. diff --git a/pom.xml b/pom.xml index a35edacd4..417d4c8ad 100644 --- a/pom.xml +++ b/pom.xml @@ -49,10 +49,53 @@ ${project.build.directory}/copilot-sdk ${copilot.sdk.clone.dir}/test + + ${copilot.sdk.clone.dir}/nodejs/node_modules/@github/copilot/index.js false + + ${skip.test.harness} + + ^1.0.36-0 + @@ -240,6 +283,35 @@ + + + install-nodejs-cli-dependencies + generate-test-resources + + exec + + + ${skip.cli.install} + npm + ${copilot.sdk.clone.dir}/nodejs + + ci + --ignore-scripts + + + @@ -253,6 +325,15 @@ ${copilot.tests.dir} ${copilot.sdk.clone.dir} + + + ${copilot.cli.path} + @@ -587,6 +668,39 @@ true + + + skip-cli-install-when-tests-skipped + + + skipTests + true + + + + true + + + + + skip-cli-install-when-maven-test-skip + + + maven.test.skip + true + + + + true + + debug