Skip to content

Commit 27c26da

Browse files
committed
bundle ql-mcp dist in new release-vsix workflow
Rename the (unreleased) vscode extension: from: codeql-development-mcp-server-vscode to: vscode-codeql-development-mcp-server Make the VSIX self-contained by bundling the MCP server entry point (server/dist/), tool query packs (server/ql/*/tools/src/), and server package.json directly into the extension. The server is now launched via `node` against the bundled JS instead of downloading via `npx` at runtime. Falls back to npx in dev environments where the bundle is absent. New files: - scripts/bundle-server.js — copies server files into extension dir - .github/workflows/build-extension.yml — CI for extension PR/push - .github/workflows/release-vsix.yml — reusable release sub-workflow with release-vsix environment, consistent with release-npm.yml and release-codeql.yml patterns Updated release.yml to call release-vsix.yml and include the VSIX in GitHub Release artifacts as codeql-development-mcp-server.vsix.
1 parent 583bad4 commit 27c26da

File tree

14 files changed

+410
-27
lines changed

14 files changed

+410
-27
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: Build Extension - CodeQL Development MCP Server
2+
3+
on:
4+
pull_request:
5+
branches: ['main']
6+
paths:
7+
- '.github/workflows/build-extension.yml'
8+
- '.node-version'
9+
- 'extensions/vscode/**'
10+
- 'server/dist/**'
11+
- 'server/ql/*/tools/src/**'
12+
push:
13+
branches: ['main']
14+
paths:
15+
- '.github/workflows/build-extension.yml'
16+
- '.node-version'
17+
- 'extensions/vscode/**'
18+
- 'server/dist/**'
19+
- 'server/ql/*/tools/src/**'
20+
workflow_dispatch:
21+
22+
permissions:
23+
contents: read
24+
25+
jobs:
26+
build-extension:
27+
name: Build Extension
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Build Extension - Checkout repository
32+
uses: actions/checkout@v6
33+
34+
- name: Build Extension - Setup Node.js environment
35+
uses: actions/setup-node@v6
36+
with:
37+
cache: 'npm'
38+
node-version-file: '.node-version'
39+
40+
- name: Build Extension - Install dependencies
41+
run: npm ci --include=optional
42+
43+
- name: Build Extension - Build server (dependency)
44+
run: npm run build -w server
45+
46+
- name: Build Extension - Run extension tests with coverage
47+
working-directory: extensions/vscode
48+
run: npm run test:coverage
49+
50+
- name: Build Extension - Bundle extension and server
51+
working-directory: extensions/vscode
52+
run: |
53+
npm run clean
54+
npm run lint
55+
npm run bundle
56+
npm run bundle:server
57+
58+
- name: Build Extension - Verify VSIX packaging
59+
working-directory: extensions/vscode
60+
run: npx @vscode/vsce package --out codeql-development-mcp-server.vsix
61+
62+
- name: Build Extension - Verify VSIX contents
63+
working-directory: extensions/vscode
64+
run: |
65+
echo "## VSIX Contents" >> $GITHUB_STEP_SUMMARY
66+
echo '```' >> $GITHUB_STEP_SUMMARY
67+
npx @vscode/vsce ls 2>&1 | head -50 >> $GITHUB_STEP_SUMMARY
68+
echo '```' >> $GITHUB_STEP_SUMMARY
69+
70+
- name: Build Extension - Check for uncommitted changes
71+
run: |
72+
if [ -n "$(git status --porcelain)" ]; then
73+
echo "❌ Uncommitted changes detected after build:"
74+
git status --porcelain
75+
git diff
76+
exit 1
77+
else
78+
echo "✅ No uncommitted changes after build"
79+
fi
80+
81+
- name: Build Extension - Summary
82+
run: |
83+
echo "## Build Extension Summary" >> $GITHUB_STEP_SUMMARY
84+
echo "✅ ESLint checks completed" >> $GITHUB_STEP_SUMMARY
85+
echo "✅ All tests passed with coverage" >> $GITHUB_STEP_SUMMARY
86+
echo "✅ Extension bundled successfully" >> $GITHUB_STEP_SUMMARY
87+
echo "✅ Server bundled into extension" >> $GITHUB_STEP_SUMMARY
88+
echo "✅ VSIX packaging verified" >> $GITHUB_STEP_SUMMARY
89+
echo "✅ No uncommitted changes detected" >> $GITHUB_STEP_SUMMARY

.github/workflows/release-vsix.yml

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
name: Release VSIX - Build and Package VS Code Extension
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
version:
7+
description: 'Release version tag (e.g., vX.Y.Z). Must start with "v".'
8+
required: true
9+
type: string
10+
outputs:
11+
release_name:
12+
description: 'The release name without "v" prefix (e.g., X.Y.Z)'
13+
value: ${{ jobs.publish-vsix.outputs.release_name }}
14+
version:
15+
description: 'The full version string with "v" prefix (e.g., vX.Y.Z)'
16+
value: ${{ jobs.publish-vsix.outputs.version }}
17+
vsix_name:
18+
description: 'The VSIX filename (e.g., codeql-development-mcp-server.vsix)'
19+
value: ${{ jobs.publish-vsix.outputs.vsix_name }}
20+
21+
# Note: This workflow is called exclusively via workflow_call from release.yml.
22+
# It does NOT have a workflow_dispatch trigger to keep release.yml as the single
23+
# entry point for all release operations. To re-build the VSIX standalone,
24+
# use workflow_dispatch on release.yml with publish_npm=false and
25+
# publish_codeql_packs=false.
26+
27+
permissions:
28+
contents: read
29+
30+
jobs:
31+
publish-vsix:
32+
name: Build and Package VSIX Extension
33+
runs-on: ubuntu-latest
34+
35+
environment: release-vsix
36+
37+
permissions:
38+
contents: read
39+
40+
outputs:
41+
release_name: ${{ steps.version.outputs.release_name }}
42+
version: ${{ steps.version.outputs.version }}
43+
vsix_name: ${{ steps.package.outputs.vsix_name }}
44+
45+
steps:
46+
- name: VSIX - Validate and parse version
47+
id: version
48+
run: |
49+
VERSION="${{ inputs.version }}"
50+
if [[ ! "${VERSION}" =~ ^v ]]; then
51+
echo "::error::Version '${VERSION}' must start with 'v'"
52+
exit 1
53+
fi
54+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
55+
echo "release_name=${VERSION#v}" >> $GITHUB_OUTPUT
56+
57+
- name: VSIX - Checkout tag
58+
uses: actions/checkout@v6
59+
with:
60+
ref: refs/tags/${{ steps.version.outputs.version }}
61+
62+
- name: VSIX - Setup Node.js
63+
uses: actions/setup-node@v6
64+
with:
65+
cache: 'npm'
66+
node-version-file: '.node-version'
67+
68+
- name: VSIX - Install dependencies
69+
run: npm ci --include=optional
70+
71+
- name: VSIX - Validate version consistency
72+
run: |
73+
RELEASE_NAME="${{ steps.version.outputs.release_name }}"
74+
EXTENSION_VERSION=$(node -e "console.log(require('./extensions/vscode/package.json').version)")
75+
if [ "${EXTENSION_VERSION}" != "${RELEASE_NAME}" ]; then
76+
echo "::error::Extension version (${EXTENSION_VERSION}) does not match release (${RELEASE_NAME})"
77+
exit 1
78+
fi
79+
echo "✅ Extension version matches release: ${RELEASE_NAME}"
80+
81+
- name: VSIX - Build server
82+
run: npm run build -w server
83+
84+
- name: VSIX - Package VSIX
85+
id: package
86+
working-directory: extensions/vscode
87+
run: |
88+
VSIX_NAME="codeql-development-mcp-server.vsix"
89+
npx @vscode/vsce package --out "${VSIX_NAME}"
90+
echo "vsix_name=${VSIX_NAME}" >> $GITHUB_OUTPUT
91+
echo "✅ Packaged ${VSIX_NAME}"
92+
93+
- name: VSIX - Verify VSIX contents
94+
working-directory: extensions/vscode
95+
run: |
96+
echo "Verifying bundled server and tool query packs..."
97+
npx @vscode/vsce ls 2>&1 | tee /tmp/vsix-contents.txt
98+
99+
# Verify critical files are included
100+
for required in \
101+
"dist/extension.cjs" \
102+
"server/dist/codeql-development-mcp-server.js" \
103+
"server/package.json" \
104+
"server/ql/javascript/tools/src/PrintAST/PrintAST.ql"; do
105+
if grep -q "${required}" /tmp/vsix-contents.txt; then
106+
echo " ✅ ${required}"
107+
else
108+
echo " ❌ Missing: ${required}"
109+
exit 1
110+
fi
111+
done
112+
113+
- name: VSIX - Upload artifact
114+
uses: actions/upload-artifact@v6
115+
with:
116+
name: codeql-development-mcp-server-vsix-${{ steps.version.outputs.version }}
117+
path: extensions/vscode/${{ steps.package.outputs.vsix_name }}
118+
119+
- name: VSIX - Summary
120+
run: |
121+
VERSION="${{ steps.version.outputs.version }}"
122+
VSIX_NAME="${{ steps.package.outputs.vsix_name }}"
123+
VSIX_SIZE=$(du -h "extensions/vscode/${VSIX_NAME}" | cut -f1)
124+
echo "## VSIX Build Summary" >> $GITHUB_STEP_SUMMARY
125+
echo "" >> $GITHUB_STEP_SUMMARY
126+
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
127+
echo "| -------- | ----- |" >> $GITHUB_STEP_SUMMARY
128+
echo "| Version | ${VERSION} |" >> $GITHUB_STEP_SUMMARY
129+
echo "| VSIX | \`${VSIX_NAME}\` |" >> $GITHUB_STEP_SUMMARY
130+
echo "| Size | ${VSIX_SIZE} |" >> $GITHUB_STEP_SUMMARY
131+
echo "" >> $GITHUB_STEP_SUMMARY
132+
echo "### Bundled Contents" >> $GITHUB_STEP_SUMMARY
133+
echo "- \`dist/extension.cjs\` — Extension entry point" >> $GITHUB_STEP_SUMMARY
134+
echo "- \`server/dist/\` — Bundled MCP server" >> $GITHUB_STEP_SUMMARY
135+
echo "- \`server/ql/*/tools/src/\` — CodeQL tool query packs" >> $GITHUB_STEP_SUMMARY
136+
echo "- \`server/package.json\` — Server package metadata" >> $GITHUB_STEP_SUMMARY

.github/workflows/release.yml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ jobs:
138138
publish_codeql_packs: ${{ needs.resolve-version.outputs.publish_codeql_packs == 'true' }}
139139
version: ${{ needs.resolve-version.outputs.version }}
140140

141+
# ─────────────────────────────────────────────────────────────────────────────
142+
# Step 3c: Build the VS Code extension VSIX
143+
#
144+
# Checks out the clean tag, builds the server and extension (including the
145+
# bundled MCP server), and packages the self-contained VSIX. Runs in parallel
146+
# with npm/CodeQL publishing since it only needs the tag.
147+
# ─────────────────────────────────────────────────────────────────────────────
148+
build-vsix:
149+
name: Build VSIX Extension
150+
needs: [resolve-version, ensure-tag]
151+
permissions:
152+
contents: read
153+
uses: ./.github/workflows/release-vsix.yml
154+
with:
155+
version: ${{ needs.resolve-version.outputs.version }}
156+
141157
# ─────────────────────────────────────────────────────────────────────────────
142158
# Step 4: Create GitHub Release
143159
#
@@ -153,7 +169,7 @@ jobs:
153169
always() && !failure() && !cancelled()
154170
&& needs.resolve-version.outputs.create_github_release == 'true'
155171
&& needs.resolve-version.outputs.publish_npm == 'true'
156-
needs: [resolve-version, ensure-tag, publish-npm, publish-codeql]
172+
needs: [resolve-version, ensure-tag, publish-npm, publish-codeql, build-vsix]
157173
runs-on: ubuntu-latest
158174

159175
permissions:
@@ -171,6 +187,12 @@ jobs:
171187
name: codeql-tool-query-packs-${{ needs.resolve-version.outputs.version }}
172188
path: dist-packs
173189

190+
- name: Release - Download VSIX artifact
191+
uses: actions/download-artifact@v6
192+
with:
193+
name: codeql-development-mcp-server-vsix-${{ needs.resolve-version.outputs.version }}
194+
path: dist-vsix
195+
174196
- name: Release - Create distribution directory
175197
run: |
176198
mkdir -p dist-package/server
@@ -217,6 +239,7 @@ jobs:
217239
files: |
218240
codeql-development-mcp-server-${{ needs.resolve-version.outputs.version }}.tar.gz
219241
dist-packs/*.tar.gz
242+
dist-vsix/codeql-development-mcp-server.vsix
220243
generate_release_notes: true
221244
tag_name: ${{ needs.resolve-version.outputs.version }}
222245

@@ -238,6 +261,7 @@ jobs:
238261
echo "| CodeQL pack publish | ⏭️ Skipped (packs bundled only) |" >> $GITHUB_STEP_SUMMARY
239262
fi
240263
echo "| Distribution archive | ✅ Created |" >> $GITHUB_STEP_SUMMARY
264+
echo "| VSIX extension | ✅ Built |" >> $GITHUB_STEP_SUMMARY
241265
echo "| GitHub Release | ✅ Created |" >> $GITHUB_STEP_SUMMARY
242266
echo "" >> $GITHUB_STEP_SUMMARY
243267
echo "### Package Contents" >> $GITHUB_STEP_SUMMARY

docs/vscode/extension.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ On activation the extension:
5454
| --------------------------------- | ---------- | -------------------------------------------------------------- |
5555
| `codeql-mcp.autoInstall` | `true` | Automatically install/update the MCP server on activation |
5656
| `codeql-mcp.serverVersion` | `"latest"` | npm version to install (`"latest"` or a specific version) |
57+
| `codeql-mcp.serverCommand` | `"node"` | Command to launch the MCP server (override for local dev) |
5758
| `codeql-mcp.watchCodeqlExtension` | `true` | Discover databases and query results from the CodeQL extension |
5859
| `codeql-mcp.additionalEnv` | `{}` | Extra environment variables for the MCP server process |
5960

extensions/vscode/.vscodeignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
.vscode-test/**
33
src/**
44
test/**
5+
scripts/**
56
node_modules/**
67
.gitignore
78
tsconfig.json
@@ -13,3 +14,7 @@ esbuild.config.js
1314
**/*.test.js
1415
**/*.map
1516
coverage/**
17+
18+
# Include server/ bundle but exclude test/examples content
19+
server/ql/*/tools/test/**
20+
server/ql/*/examples/**

extensions/vscode/eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,6 @@ export default [
101101
},
102102
},
103103
{
104-
ignores: ['dist/', 'node_modules/', 'esbuild.config.js'],
104+
ignores: ['dist/', 'node_modules/', 'esbuild.config.js', 'scripts/'],
105105
},
106106
];

extensions/vscode/package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "codeql-development-mcp-server-vscode",
2+
"name": "vscode-codeql-development-mcp-server",
33
"displayName": "CodeQL Development MCP Server",
44
"description": "Automatically installs, configures, and manages the CodeQL Development MCP Server in VS Code.",
55
"version": "2.24.1",
@@ -60,14 +60,14 @@
6060
},
6161
"codeql-mcp.serverCommand": {
6262
"type": "string",
63-
"default": "npx",
64-
"description": "Command to launch the MCP server. Override to 'node' for local development builds."
63+
"default": "node",
64+
"description": "Command to launch the MCP server. The default 'node' runs the bundled server. Override to 'npx' to download from npm, or provide a custom path."
6565
},
6666
"codeql-mcp.serverArgs": {
6767
"type": "array",
6868
"items": { "type": "string" },
6969
"default": [],
70-
"description": "Custom arguments for the MCP server command. When empty, defaults to ['-y', 'codeql-development-mcp-server']. Set to e.g. ['/path/to/server/dist/codeql-development-mcp-server.js'] when using serverCommand='node' for local development."
70+
"description": "Custom arguments for the MCP server command. When empty, the bundled server entry point is used automatically. Set to e.g. ['/path/to/server/dist/codeql-development-mcp-server.js'] for local development."
7171
},
7272
"codeql-mcp.watchCodeqlExtension": {
7373
"type": "boolean",
@@ -110,12 +110,15 @@
110110
"scripts": {
111111
"build": "npm run clean && npm run lint && npm run bundle",
112112
"bundle": "node esbuild.config.js",
113+
"bundle:server": "node scripts/bundle-server.js",
113114
"clean": "rm -rf dist",
114115
"lint": "eslint src/ test/",
115116
"lint:fix": "eslint src/ test/ --fix",
117+
"package": "vsce package --out codeql-development-mcp-server.vsix",
116118
"test": "vitest --run",
117119
"test:coverage": "vitest --run --coverage",
118120
"test:watch": "vitest --watch",
121+
"vscode:prepublish": "npm run clean && npm run lint && npm run bundle && npm run bundle:server",
119122
"watch": "node esbuild.config.js --watch"
120123
},
121124
"devDependencies": {
@@ -124,6 +127,7 @@
124127
"@types/node": "^22.15.0",
125128
"@types/vscode": "^1.99.0",
126129
"@vitest/coverage-v8": "^4.0.18",
130+
"@vscode/vsce": "^3.3.2",
127131
"esbuild": "^0.27.3",
128132
"eslint": "^9.39.2",
129133
"eslint-config-prettier": "^10.1.8",

0 commit comments

Comments
 (0)