Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,9 @@ jobs:
path: extension/.vscode-test/
key: ${{ runner.os }}-vscode-test-${{ hashFiles('extension/package-lock.json') }}

- name: Build server
- name: Build and test
run: ./gradlew build --info

- name: Install dependencies
run: cd extension && npm ci --ignore-scripts

- name: Lint
run: cd extension && npm run lint

- name: Run unit tests
run: cd extension && npm run test:unit

- name: Run integration tests
run: cd extension && xvfb-run -a npm run test:integration

- name: SonarQube Scan
if: ${{ env.DEFAULT_OS == matrix.os }}
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
/build/
/server/build/
/.settings/org.eclipse.buildship.core.prefs
/server/bin/
10 changes: 7 additions & 3 deletions doc/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ material advantage for this standalone, standard-protocol server.

The server is a Gradle project using the Groovy DSL and the `application`
plugin. Gradle produces the runnable distribution that the VS Code extension
launches. The server targets Java 21. The OpenFastTrace Gradle plugin runs the
requirements trace as an independent verification task and does not define the
language-server build.
launches. The server targets Java 21. The VS Code extension is also a Gradle
subproject: its lifecycle tasks install locked Node.js dependencies, compile,
lint, and test the TypeScript adapter. When available, extension integration
tests run under Xvfb; otherwise they run directly. Consequently, `./gradlew
build` verifies both the server and extension. The OpenFastTrace Gradle plugin
runs the requirements trace as an independent verification task and does not
define the language-server build.

VS Code extensions execute in a Node.js extension host and do not receive a
Java runtime from VS Code. The extension therefore obtains a Java 21 runtime
Expand Down
30 changes: 30 additions & 0 deletions doc/developer_guide.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Developer Guide

## Build And Test

Prerequisites:

* Java 21
* Node.js 24 and its bundled `npm`
* On Linux, `xvfb-run` is optional and enables headless VS Code integration
tests

Build and test the complete server and extension with one command:

```sh
./gradlew build
```

The `extension` Gradle subproject installs locked Node.js dependencies with
`npm ci --ignore-scripts`, then compiles, lints, and tests the extension. Use
these focused tasks when needed:

```sh
./gradlew :extension:compileExtension
./gradlew :extension:lintExtension
./gradlew :extension:unitTestExtension
./gradlew :extension:integrationTestExtension
```

When `xvfb-run` is available, `integrationTestExtension` launches the VS Code
test runtime through `xvfb-run -a`; otherwise it invokes the npm
integration-test script directly.

## Trace Requirements

Run the current MVP requirements trace locally with Java 17 or later:
Expand Down
68 changes: 68 additions & 0 deletions extension/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
plugins {
id 'base'
}

def npmCommand = System.getProperty('os.name').toLowerCase().contains('windows') ? 'npm.cmd' : 'npm'
def isLinux = System.getProperty('os.name').toLowerCase().contains('linux')
def xvfbRun = isLinux ? System.getenv('PATH').split(File.pathSeparator)
.collect { new File(it, 'xvfb-run') }
.find { it.canExecute() } : null

def npmInstall = tasks.register('npmInstall', Exec) {
group = 'build setup'
description = 'Installs the extension Node.js dependencies.'
commandLine npmCommand, 'ci', '--ignore-scripts'
inputs.files('package.json', 'package-lock.json')
outputs.dir('node_modules')
}

def compileExtension = tasks.register('compileExtension', Exec) {
group = 'build'
description = 'Compiles the VS Code extension.'
dependsOn npmInstall
commandLine npmCommand, 'run', 'compile'
inputs.files('package.json', 'tsconfig.json')
inputs.dir('src')
outputs.dir('out')
}

def lintExtension = tasks.register('lintExtension', Exec) {
group = 'verification'
description = 'Lints the VS Code extension.'
dependsOn npmInstall
commandLine npmCommand, 'run', 'lint'
inputs.files('package.json', 'eslint.config.mjs', 'tsconfig.json')
inputs.dir('src')
}

def unitTestExtension = tasks.register('unitTestExtension', Exec) {
group = 'verification'
description = 'Runs the VS Code extension unit tests.'
dependsOn compileExtension
commandLine npmCommand, 'run', 'test:unit'
inputs.files('package.json', 'tsconfig.json')
inputs.dir('src')
outputs.file('coverage/unit.lcov')
}

def integrationTestExtension = tasks.register('integrationTestExtension', Exec) {
group = 'verification'
description = 'Runs the VS Code extension integration tests.'
dependsOn compileExtension
if (xvfbRun) {
commandLine xvfbRun.absolutePath, '-a', npmCommand, 'run', 'test:integration'
} else {
commandLine npmCommand, 'run', 'test:integration'
}
inputs.files('package.json', 'tsconfig.json')
inputs.dir('src')
outputs.dir('coverage/integration')
}

tasks.named('assemble') {
dependsOn compileExtension
}

tasks.named('check') {
dependsOn lintExtension, unitTestExtension, integrationTestExtension
}