Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bb8bbe3
On branch edburns/80-java-monorepo-add-01 Commence work on https://gi…
edburns May 13, 2026
f88c345
refine to get ready for plan review
edburns May 13, 2026
6787399
On branch edburns/80-java-monorepo-add-01 Put the plan first.
edburns May 13, 2026
baae90b
On branch edburns/80-java-monorepo-add-01 https://github.com/github/c…
edburns May 13, 2026
a057b12
test: verify gpg signing
edburns May 13, 2026
745699a
On branch edburns/80-java-monorepo-add-01
edburns May 13, 2026
49dd28e
Per https://github.com/github/copilot-sdk-partners/issues/89 no per-l…
edburns May 14, 2026
3293445
Update progress
edburns May 14, 2026
9212a54
Define gh-pages as WONTFIX
edburns May 15, 2026
5d854c0
Branch protection
edburns May 15, 2026
e4116e0
new prompts
edburns May 15, 2026
3b51fb9
Sync regexp changes
edburns May 15, 2026
8b51fc6
ghcp-sp-95-branch-protection
edburns May 15, 2026
5081b6f
ghcp-sp-95-branch-protection
edburns May 15, 2026
542769e
Complete phase 0
edburns May 15, 2026
a3bc7c4
Start on dd-2998002
edburns May 15, 2026
c7bfea6
Phase 1: .githooks and instructions
edburns May 18, 2026
4556704
test: verify gpg signing
edburns May 13, 2026
4de2e56
Fixes https://github.com/github/copilot-sdk-partners/issues/95
edburns May 18, 2026
9c220c8
Branch protuction.
edburns May 18, 2026
63d9430
Mark more completed
edburns May 18, 2026
56d5cdb
Phase 1 plan
edburns May 18, 2026
417075f
Copy Java SDK source files into java/ directory
edburns May 18, 2026
8fbfa01
Update pom.xml to use local test harness instead of git clone
edburns May 18, 2026
aa013cc
Document need to restore the POM property updating
edburns May 19, 2026
908829c
Document copilot --yolo progress
edburns May 19, 2026
e353c87
Ignore log files
edburns May 19, 2026
57c85b3
Copy over https://github.com/github/copilot-sdk-java/pull/216
edburns May 19, 2026
db1892e
Restore antrun git-clone mechanism and add missing codegen files
edburns May 19, 2026
3169646
Prepare for Phase 2
edburns May 19, 2026
01146fe
Add java-sdk-tests.yml adapted from build-test.yml
edburns May 19, 2026
ce49933
Add Java job to codegen-check.yml
edburns May 19, 2026
d4cbd23
Add java-codegen-fix.md agentic workflow
edburns May 19, 2026
1d128a6
Add Java tooling to copilot-setup-steps.yml
edburns May 19, 2026
f961248
Add Maven and Java codegen npm ecosystems to dependabot.yaml
edburns May 19, 2026
8901b2a
execute phase 2
edburns May 19, 2026
5b7d7bf
Update java-sdk-tests.yml: address review concerns
edburns May 19, 2026
061d770
Revert codegen-check.yml; create standalone java-codegen-check.yml
edburns May 20, 2026
640da81
copilot-setup-steps: pin gh-aw version and enable pre-commit hooks
edburns May 20, 2026
95ecdf8
dependabot: add ignore rules and groups for Java entries
edburns May 20, 2026
aaa3db8
Ready to test java-sdk-tests.yml
edburns May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 29 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh
#
# Pre-commit hook that runs Spotless check on the Java SDK when Java source
# files are staged. Only triggers if changes exist under java/src/.
#
# To install this hook, run from the repository root:
# git config core.hooksPath .githooks
#

# Only run Spotless if staged changes include Java source files under java/src/
if ! git diff --cached --name-only | grep -q '^java/src/'; then
exit 0
fi

echo "Running Spotless check on java/ ..."

# Run spotless check from the java directory
(cd java && mvn spotless:check -q)

if [ $? -ne 0 ]; then
echo ""
echo "❌ Spotless check failed!"
echo " Run 'cd java && mvn spotless:apply' to fix formatting issues."
echo ""
exit 1
fi

echo "✓ Spotless check passed"
exit 0
182 changes: 182 additions & 0 deletions .github/actions/java-test-report/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
name: "Java Test Report"
description: "Generate and publish test reports with summary for Java SDK tests."
inputs:
report-path:
description: "Path to the test report XML files (glob pattern)"
required: false
default: "java/target/surefire-reports*/TEST-*.xml"
jacoco-path:
description: "Path to the JaCoCo XML report"
required: false
default: "java/target/site/jacoco-coverage/jacoco.xml"
jacoco-csv-path:
description: "Path to the JaCoCo CSV report"
required: false
default: "java/target/site/jacoco-coverage/jacoco.csv"
check-name:
description: "Name for the check run"
required: false
default: "Java SDK Test Results"
runs:
using: "composite"
steps:
- name: Generate Test Summary
shell: bash
run: |
echo "## 🧪 Copilot Java SDK :: Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

if ls ${{ inputs.report-path }} 1>/dev/null 2>&1; then
TESTS_RUN=$(grep -h "tests=" ${{ inputs.report-path }} 2>/dev/null | sed 's/.*tests="\([0-9]*\)".*/\1/' | awk '{s+=$1} END {print s}')
FAILURES=$(grep -h "failures=" ${{ inputs.report-path }} 2>/dev/null | sed 's/.*failures="\([0-9]*\)".*/\1/' | awk '{s+=$1} END {print s}')
ERRORS=$(grep -h "errors=" ${{ inputs.report-path }} 2>/dev/null | sed 's/.*errors="\([0-9]*\)".*/\1/' | awk '{s+=$1} END {print s}')
SKIPPED=$(grep -h "skipped=" ${{ inputs.report-path }} 2>/dev/null | sed 's/.*skipped="\([0-9]*\)".*/\1/' | awk '{s+=$1} END {print s}')

TESTS_RUN=${TESTS_RUN:-0}
FAILURES=${FAILURES:-0}
ERRORS=${ERRORS:-0}
SKIPPED=${SKIPPED:-0}
PASSED=$((TESTS_RUN - FAILURES - ERRORS - SKIPPED))

if [ "$FAILURES" -eq 0 ] && [ "$ERRORS" -eq 0 ]; then
echo "### ✅ All tests passed!" >> $GITHUB_STEP_SUMMARY
else
echo "### ❌ Some tests failed" >> $GITHUB_STEP_SUMMARY
fi

echo "" >> $GITHUB_STEP_SUMMARY
echo "| Metric | Count |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| ✅ Passed | $PASSED |" >> $GITHUB_STEP_SUMMARY
echo "| ❌ Failed | $FAILURES |" >> $GITHUB_STEP_SUMMARY
echo "| 💥 Errors | $ERRORS |" >> $GITHUB_STEP_SUMMARY
echo "| ⏭️ Skipped | $SKIPPED |" >> $GITHUB_STEP_SUMMARY
echo "| 📊 Total | $TESTS_RUN |" >> $GITHUB_STEP_SUMMARY

echo "" >> $GITHUB_STEP_SUMMARY
echo "### Test Classes" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Class | Tests | Passed | Failed | Errors | Time |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|--------|--------|--------|------|" >> $GITHUB_STEP_SUMMARY

for file in ${{ inputs.report-path }}; do
if [ -f "$file" ]; then
CLASS=$(basename "$file" .xml | sed 's/TEST-//')
T=$(grep -o 'tests="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
F=$(grep -o 'failures="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
E=$(grep -o 'errors="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
TIME=$(grep -o 'time="[0-9.]*"' "$file" | head -1 | sed 's/[^0-9.]//g')
P=$((T - F - E))

STATUS="✅"
if [ "${F:-0}" -gt 0 ] || [ "${E:-0}" -gt 0 ]; then
STATUS="❌"
fi

echo "| $STATUS $CLASS | ${T:-0} | ${P:-0} | ${F:-0} | ${E:-0} | ${TIME:-0}s |" >> $GITHUB_STEP_SUMMARY
fi
done
else
echo "⚠️ No test reports found at ${{ inputs.report-path }}" >> $GITHUB_STEP_SUMMARY
fi

- name: Generate Coverage Summary
shell: bash
run: |
JACOCO_XML="${{ inputs.jacoco-path }}"
JACOCO_CSV="${{ inputs.jacoco-csv-path }}"

if [ -f "$JACOCO_XML" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "## 📊 Code Coverage" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

# JaCoCo XML may be on a single line - split it for parsing
# Extract report-level counters (last occurrence of each type before </report>)
extract_counter() {
local type=$1
local field=$2
# Split XML on > to get one tag per line, find counter, extract value
sed 's/>/>\n/g' "$JACOCO_XML" | grep "<counter type=\"$type\"" | tail -1 | sed "s/.*$field=\"\([0-9]*\)\".*/\1/"
}

INSTR_MISSED=$(extract_counter "INSTRUCTION" "missed")
INSTR_COVERED=$(extract_counter "INSTRUCTION" "covered")

BRANCH_MISSED=$(extract_counter "BRANCH" "missed")
BRANCH_COVERED=$(extract_counter "BRANCH" "covered")

LINE_MISSED=$(extract_counter "LINE" "missed")
LINE_COVERED=$(extract_counter "LINE" "covered")

METHOD_MISSED=$(extract_counter "METHOD" "missed")
METHOD_COVERED=$(extract_counter "METHOD" "covered")

CLASS_MISSED=$(extract_counter "CLASS" "missed")
CLASS_COVERED=$(extract_counter "CLASS" "covered")

# Calculate percentages
calc_pct() {
local covered=$1
local missed=$2
if [ -n "$covered" ] && [ -n "$missed" ]; then
local total=$((covered + missed))
if [ "$total" -gt 0 ]; then
echo "scale=1; $covered * 100 / $total" | bc
else
echo "0"
fi
else
echo "N/A"
fi
}

INSTR_PCT=$(calc_pct "${INSTR_COVERED:-0}" "${INSTR_MISSED:-0}")
BRANCH_PCT=$(calc_pct "${BRANCH_COVERED:-0}" "${BRANCH_MISSED:-0}")
LINE_PCT=$(calc_pct "${LINE_COVERED:-0}" "${LINE_MISSED:-0}")
METHOD_PCT=$(calc_pct "${METHOD_COVERED:-0}" "${METHOD_MISSED:-0}")
CLASS_PCT=$(calc_pct "${CLASS_COVERED:-0}" "${CLASS_MISSED:-0}")

echo "| Metric | Covered | Missed | Coverage |" >> $GITHUB_STEP_SUMMARY
echo "|--------|---------|--------|----------|" >> $GITHUB_STEP_SUMMARY
echo "| 📝 Instructions | ${INSTR_COVERED:-0} | ${INSTR_MISSED:-0} | ${INSTR_PCT}% |" >> $GITHUB_STEP_SUMMARY
echo "| 🌿 Branches | ${BRANCH_COVERED:-0} | ${BRANCH_MISSED:-0} | ${BRANCH_PCT}% |" >> $GITHUB_STEP_SUMMARY
echo "| 📏 Lines | ${LINE_COVERED:-0} | ${LINE_MISSED:-0} | ${LINE_PCT}% |" >> $GITHUB_STEP_SUMMARY
echo "| 🔧 Methods | ${METHOD_COVERED:-0} | ${METHOD_MISSED:-0} | ${METHOD_PCT}% |" >> $GITHUB_STEP_SUMMARY
echo "| 📦 Classes | ${CLASS_COVERED:-0} | ${CLASS_MISSED:-0} | ${CLASS_PCT}% |" >> $GITHUB_STEP_SUMMARY

if [ -f "$JACOCO_CSV" ]; then
extract_instruction_scope() {
local scope=$1
awk -F',' -v scope="$scope" -v generated_prefix="com.github.copilot.sdk.generated" '
NR > 1 {
is_generated = index($2, generated_prefix) == 1
if ((scope == "generated" && is_generated) ||
(scope == "handwritten" && !is_generated)) {
missed += $4
covered += $5
}
}
END { print covered + 0 "," missed + 0 }
' "$JACOCO_CSV"
}

IFS=, read -r HANDWRITTEN_COVERED HANDWRITTEN_MISSED <<< "$(extract_instruction_scope handwritten)"
IFS=, read -r GENERATED_COVERED GENERATED_MISSED <<< "$(extract_instruction_scope generated)"
HANDWRITTEN_PCT=$(calc_pct "${HANDWRITTEN_COVERED:-0}" "${HANDWRITTEN_MISSED:-0}")
GENERATED_PCT=$(calc_pct "${GENERATED_COVERED:-0}" "${GENERATED_MISSED:-0}")

echo "" >> $GITHUB_STEP_SUMMARY
echo "### Coverage by Code Origin (Instructions)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Origin | Covered | Missed | Coverage |" >> $GITHUB_STEP_SUMMARY
echo "|--------|---------|--------|----------|" >> $GITHUB_STEP_SUMMARY
echo "| ✍️ Handwritten | ${HANDWRITTEN_COVERED:-0} | ${HANDWRITTEN_MISSED:-0} | ${HANDWRITTEN_PCT}% |" >> $GITHUB_STEP_SUMMARY
echo "| 🤖 Generated | ${GENERATED_COVERED:-0} | ${GENERATED_MISSED:-0} | ${GENERATED_PCT}% |" >> $GITHUB_STEP_SUMMARY
fi
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "## 📊 Code Coverage" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ No JaCoCo report found at $JACOCO_XML" >> $GITHUB_STEP_SUMMARY
fi
11 changes: 8 additions & 3 deletions .github/aw/actions-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@
"version": "v8",
"sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd"
},
"actions/github-script@v9.0.0": {
"repo": "actions/github-script",
"version": "v9.0.0",
"sha": "3a2844b7e9c422d3c10d287c895573f7108da1b3"
},
"actions/upload-artifact@v7.0.0": {
"repo": "actions/upload-artifact",
"version": "v7.0.0",
"sha": "bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"
},
"github/gh-aw-actions/setup@v0.67.4": {
"github/gh-aw-actions/setup@v0.74.4": {
"repo": "github/gh-aw-actions/setup",
"version": "v0.67.4",
"sha": "9d6ae06250fc0ec536a0e5f35de313b35bad7246"
"version": "v0.74.4",
"sha": "d3abfe96a194bce3a523ed2093ddedd5704cdf62"
},
"github/gh-aw/actions/setup@v0.52.1": {
"repo": "github/gh-aw/actions/setup",
Expand Down
19 changes: 12 additions & 7 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

## Big picture 🔧

- The repo implements language SDKs (Node/TS, Python, Go, .NET) that speak to the **Copilot CLI** via **JSON‑RPC** (see `README.md` and `nodejs/src/client.ts`).
- Typical flow: your App → SDK client → JSON-RPC → Copilot CLI (server mode). The CLI must be installed or you can connect to an external CLI server via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`).
- The repo implements language SDKs (Node/TS, Python, Go, .NET, Java) that speak to the **Copilot CLI** via **JSON‑RPC** (see `README.md` and `nodejs/src/client.ts`).
- Typical flow: your App → SDK client → JSON-RPC → Copilot CLI (server mode). The CLI must be installed or you can connect to an external CLI server via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`, Java: `cliUrl`).

## Most important files to read first 📚

- Top-level: `README.md` (architecture + quick start)
- Language entry points: `nodejs/src/client.ts`, `python/README.md`, `go/README.md`, `dotnet/README.md`
- Java: `java/README.md`, `java/pom.xml`
- Test harness & E2E: `test/harness/*`, Python harness wrapper `python/e2e/testharness/proxy.py`
- Schemas & type generation: `nodejs/scripts/generate-session-types.ts`
- Session snapshots used by E2E: `test/snapshots/` (used by the replay proxy)
Expand All @@ -26,12 +27,15 @@
- Go: `cd go && go test ./...`
- .NET: `cd dotnet && dotnet test test/GitHub.Copilot.SDK.Test.csproj`
- **.NET testing note:** Never add `InternalsVisibleTo` to any project file when writing tests. Tests must only access public APIs.
- Java: `cd java && mvn clean verify` (full build + tests), `mvn spotless:apply` (format code before commit)
- **Java testing note:** Always use `mvn verify` without `-q` and without piping through `grep`. Never add `InternalsVisibleTo` equivalent — tests must only access public APIs.

## Testing & E2E tips ⚙️

- E2E runs against a local **replaying CAPI proxy** (see `test/harness/server.ts`). Most language E2E harnesses spawn that server automatically (see `python/e2e/testharness/proxy.py`).
- Tests rely on YAML snapshot exchanges under `test/snapshots/` — to add test scenarios, add or edit the appropriate YAML files and update tests.
- The harness prints `Listening: http://...` — tests parse this URL to configure CLI or proxy.
- Java E2E tests use `E2ETestContext` which manages a `CapiProxy` (Node.js replaying proxy). The harness is cloned during Maven's `generate-test-resources` phase to `java/target/copilot-sdk/`.

## Project-specific conventions & patterns ✅

Expand All @@ -42,13 +46,14 @@

## Integration & environment notes ⚠️

- The SDK requires a Copilot CLI installation or an external server reachable via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`) or `COPILOT_CLI_PATH`.
- The SDK requires a Copilot CLI installation or an external server reachable via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`, Java: `cliUrl`) or `COPILOT_CLI_PATH`.
- Some scripts (typegen, formatting) call external tools: `gofmt`, `dotnet format`, `tsx` (available via npm), `quicktype`/`quicktype-core` (used by the Node typegen script), and `prettier` (provided as an npm devDependency). Most of these are available through the repo's package scripts or devDependencies—run `just install` (and `cd nodejs && npm ci`) to install them. Ensure the required tools are available in CI / developer machines.
- Tests may assume `node >= 18`, `python >= 3.9`, platform differences handled (Windows uses `shell=True` for npx in harness).
- Java requires JDK 17+ and Maven 3.9+. Java E2E tests also require Node.js (for the replay proxy).

## Where to add new code or tests 🧭

- SDK code: `nodejs/src`, `python/copilot`, `go`, `dotnet/src`, `rust/src`
- Unit tests: `nodejs/test`, `python/*`, `go/*`, `dotnet/test`, `rust/tests`
- E2E tests: `*/e2e/` folders that use the shared replay proxy and `test/snapshots/`
- Generated types: update schema in `@github/copilot` then run `cd nodejs && npm run generate:session-types` and commit generated files in `src/generated` or language generated location.
- SDK code: `nodejs/src`, `python/copilot`, `go`, `dotnet/src`, `rust/src`, `java/src/main/java`
- Unit tests: `nodejs/test`, `python/*`, `go/*`, `dotnet/test`, `rust/tests`, `java/src/test/java`
- E2E tests: `*/e2e/` folders that use the shared replay proxy and `test/snapshots/`, `java/src/test/java/**/e2e/`
- Generated types: update schema in `@github/copilot` then run `cd nodejs && npm run generate:session-types` and commit generated files in `src/generated` or language generated location. Java generated types: `java/src/generated/java`
29 changes: 29 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ updates:
directory: '/'
multi-ecosystem-group: 'all'
patterns: ['*']
ignore:
# gh-aw generated files — action SHAs are managed by `gh aw compile`
# via .github/aw/actions-lock.json, not by Dependabot.
# Dependabot's find-and-replace breaks lockfile metadata headers.
- dependency-name: "actions/github-script"
- dependency-name: "github/gh-aw-actions"
- package-ecosystem: 'devcontainers'
directory: '/'
multi-ecosystem-group: 'all'
Expand Down Expand Up @@ -36,3 +42,26 @@ updates:
directory: '/dotnet'
multi-ecosystem-group: 'all'
patterns: ['*']
# Java dependencies
- package-ecosystem: 'maven'
directory: '/java'
schedule:
interval: 'weekly'
ignore:
# Major version bumps often drop Java 17 support or have breaking
# API changes. These must be evaluated and applied manually.
- dependency-name: "*"
update-types: ["version-update:semver-major"]
groups:
java-maven-deps:
patterns:
- "*"
# Java codegen dependencies
- package-ecosystem: 'npm'
directory: '/java/scripts/codegen'
schedule:
interval: 'weekly'
groups:
java-codegen-deps:
patterns:
- "*"
Loading
Loading