Skip to content

Commit fd09a81

Browse files
CI and test fixes (#3)
* Fix Node test startup on Windows * Fix Go tests * Fix Python tests * Remove Python egg-info dir which shouldn't be tracked in Git * Publish packages only from main * Fix formatting * Add Windows CI job. Simplify Python CI matrix to just 3.12 (latest documented supported version) * Avoid duplicate CI jobs (push and pull_request) * Avoid line endings issues in CI * Clean up defaults * Similarly don't run go fmt on Windows due to line endings differences * Fix Python tests in Windows CI job
1 parent 05ffbb8 commit fd09a81

18 files changed

Lines changed: 72 additions & 115 deletions

.github/workflows/publish.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: Publish package to GitHub Packages
22
on:
33
push:
4+
branches:
5+
- main
46
jobs:
57
build:
68
runs-on: ubuntu-latest

.github/workflows/sdk-e2e-tests.yml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,29 @@ name: "SDK E2E Tests"
22

33
env:
44
HUSKY: 0
5+
PYTHONUTF8: 1
56

67
on:
78
push:
9+
branches: [main]
810
pull_request:
911
workflow_dispatch:
1012
merge_group:
1113

1214
permissions:
1315
contents: read
1416

15-
defaults:
16-
run:
17-
shell: bash
18-
1917
jobs:
2018
nodejs-sdk:
2119
name: "Node.js SDK Tests"
2220
strategy:
2321
fail-fast: false
2422
matrix:
25-
os: [ubuntu-latest, macos-latest]
23+
os: [ubuntu-latest, macos-latest, windows-latest]
2624
runs-on: ${{ matrix.os }}
2725
defaults:
2826
run:
27+
shell: bash
2928
working-directory: ./nodejs
3029
steps:
3130
- uses: actions/checkout@v6
@@ -38,6 +37,7 @@ jobs:
3837
run: npm ci --ignore-scripts
3938

4039
- name: Run prettier check
40+
if: runner.os == 'Linux'
4141
run: npm run format:check
4242

4343
- name: Run ESLint
@@ -57,10 +57,11 @@ jobs:
5757
strategy:
5858
fail-fast: false
5959
matrix:
60-
os: [ubuntu-latest, macos-latest]
60+
os: [ubuntu-latest, macos-latest, windows-latest]
6161
runs-on: ${{ matrix.os }}
6262
defaults:
6363
run:
64+
shell: bash
6465
working-directory: ./go
6566
steps:
6667
- uses: actions/checkout@v6
@@ -70,6 +71,7 @@ jobs:
7071
go-version: "1.21"
7172

7273
- name: Run go fmt
74+
if: runner.os == 'Linux'
7375
working-directory: ./go
7476
run: |
7577
go fmt ./...
@@ -81,6 +83,7 @@ jobs:
8183
echo "✅ go fmt produced no changes"
8284
8385
- name: Install golangci-lint
86+
if: runner.os == 'Linux'
8487
uses: golangci/golangci-lint-action@v9
8588
with:
8689
working-directory: ./go
@@ -98,18 +101,18 @@ jobs:
98101
strategy:
99102
fail-fast: false
100103
matrix:
101-
os: [ubuntu-latest, macos-latest]
102-
python-version: ["3.9", "3.10", "3.11"]
104+
os: [ubuntu-latest, macos-latest, windows-latest]
103105
runs-on: ${{ matrix.os }}
104106
defaults:
105107
run:
108+
shell: bash
106109
working-directory: ./python
107110
steps:
108111
- uses: actions/checkout@v6
109112
- uses: ./.github/actions/setup-copilot
110113
- uses: actions/setup-python@v6
111114
with:
112-
python-version: ${{ matrix.python-version }}
115+
python-version: "3.12"
113116

114117
- name: Set up uv
115118
uses: astral-sh/setup-uv@v7

go/client.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os/exec"
1010
"regexp"
1111
"strconv"
12+
"strings"
1213
"sync"
1314
"time"
1415

@@ -346,7 +347,15 @@ func (c *Client) startCLIServer() error {
346347
args = append(args, "--port", strconv.Itoa(c.options.Port))
347348
}
348349

349-
c.process = exec.Command(c.options.CLIPath, args...)
350+
// If CLIPath is a .js file, run it with node
351+
// Note we can't rely on the shebang as Windows doesn't support it
352+
command := c.options.CLIPath
353+
if strings.HasSuffix(c.options.CLIPath, ".js") {
354+
command = "node"
355+
args = append([]string{c.options.CLIPath}, args...)
356+
}
357+
358+
c.process = exec.Command(command, args...)
350359

351360
// Set working directory if specified
352361
if c.options.Cwd != "" {

go/client_test.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,18 +240,10 @@ func TestClient(t *testing.T) {
240240

241241
// Helper function to find CLI path
242242
func findCLIPath() string {
243-
// Try relative path from SDK location
244-
possiblePaths := []string{
245-
"../../dist-cli/index.js",
246-
"../../../dist-cli/index.js",
247-
"./dist-cli/index.js",
248-
}
249-
250-
for _, p := range possiblePaths {
251-
abs, _ := filepath.Abs(p)
252-
if fileExists(abs) {
253-
return abs
254-
}
243+
// Look for CLI in sibling nodejs directory's node_modules
244+
abs, _ := filepath.Abs("../nodejs/node_modules/@github/copilot/index.js")
245+
if fileExists(abs) {
246+
return abs
255247
}
256248

257249
return ""

nodejs/.prettierrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"printWidth": 100,
66
"tabWidth": 4,
77
"useTabs": false,
8-
"arrowParens": "always"
8+
"arrowParens": "always",
9+
"endOfLine": "lf"
910
}

nodejs/src/client.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,13 @@ export class CopilotClient {
429429
const envWithoutNodeDebug = { ...this.options.env };
430430
delete envWithoutNodeDebug.NODE_DEBUG;
431431

432-
this.cliProcess = spawn(this.options.cliPath, args, {
432+
// If cliPath is a .js file, spawn it with node
433+
// Note that we can't rely on the shebang as Windows doesn't support it
434+
const isJsFile = this.options.cliPath.endsWith(".js");
435+
const command = isJsFile ? "node" : this.options.cliPath;
436+
const spawnArgs = isJsFile ? [this.options.cliPath, ...args] : args;
437+
438+
this.cliProcess = spawn(command, spawnArgs, {
433439
stdio: this.options.useStdio
434440
? ["pipe", "pipe", "pipe"]
435441
: ["ignore", "pipe", "pipe"],

nodejs/src/query.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,19 @@ export async function* query(options: QueryOptions): AsyncGenerator<SessionEvent
167167
const systemMessageConfig = systemMessage
168168
? ({ mode: "replace", content: systemMessage } satisfies SystemMessageConfig)
169169
: undefined;
170-
session = await client.createSession({ model, tools, systemMessage: systemMessageConfig });
170+
session = await client.createSession({
171+
model,
172+
tools,
173+
systemMessage: systemMessageConfig,
174+
});
171175
}
172176

173177
// Use EventEmitter to convert session events to async iterator
174178
const eventEmitter = new EventEmitter<{ data: [SessionEvent] }>();
175179
session.on((event) => eventEmitter.emit("data", event));
176-
const eventIterator = on(eventEmitter, "data", { signal: abortController.signal }) as SessionEventIterator;
180+
const eventIterator = on(eventEmitter, "data", {
181+
signal: abortController.signal,
182+
}) as SessionEventIterator;
177183

178184
session.send({ prompt, attachments }).catch((sendError) => {
179185
!turnFinished && eventIterator.throw!(sendError);
@@ -195,7 +201,7 @@ export async function* query(options: QueryOptions): AsyncGenerator<SessionEvent
195201
throw new Error(
196202
typeof event.data === "object" && event.data && "message" in event.data
197203
? String(event.data.message)
198-
: "Unknown error",
204+
: "Unknown error"
199205
);
200206
}
201207

nodejs/test/client.test.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,14 @@
44
* Tests the CopilotClient class - the main SDK entry point
55
*/
66

7-
import fs from "fs";
87
import path from "path";
98
import { fileURLToPath } from "url";
109
import { afterEach, describe, expect, it } from "vitest";
1110
import { CopilotClient, SystemMessageConfig } from "../src/index.js";
1211

1312
const __filename = fileURLToPath(import.meta.url);
1413
const __dirname = path.dirname(__filename);
15-
const CLI_PATH = path.resolve(__dirname, "../../../dist-cli/index.js");
16-
17-
// Verify CLI exists before running tests
18-
if (!fs.existsSync(CLI_PATH)) {
19-
throw new Error(
20-
`CLI not found at ${CLI_PATH}. Run 'npm run build' in the root directory first.`
21-
);
22-
}
14+
const CLI_PATH = path.resolve(__dirname, "../node_modules/@github/copilot/index.js");
2315

2416
describe("CopilotClient", () => {
2517
let client: CopilotClient | null = null;

python/copilot/client.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,15 @@ async def ping(self, message: Optional[str] = None) -> dict:
233233

234234
async def _start_cli_server(self) -> None:
235235
"""Start the CLI server process"""
236-
args = [self.options["cli_path"], "--server", "--log-level", self.options["log_level"]]
236+
cli_path = self.options["cli_path"]
237+
args = ["--server", "--log-level", self.options["log_level"]]
238+
239+
# If cli_path is a .js file, run it with node
240+
# Note that we can't rely on the shebang as Windows doesn't support it
241+
if cli_path.endswith(".js"):
242+
args = ["node", cli_path] + args
243+
else:
244+
args = [cli_path] + args
237245

238246
# Choose transport mode
239247
if self.options["use_stdio"]:

python/copilot_sdk.egg-info/PKG-INFO

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)