Skip to content

Commit 0d30772

Browse files
authored
Merge pull request #18 from rubyatscale/update/modernize-tooling
Modernize CI, linting, and test tooling
2 parents 473acad + ca5a1f8 commit 0d30772

14 files changed

Lines changed: 1470 additions & 1125 deletions

.eslintrc.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"parserOptions": {
5+
"ecmaVersion": 2019,
6+
"sourceType": "module"
7+
},
8+
"plugins": ["@typescript-eslint"],
9+
"rules": {
10+
"curly": "error",
11+
"default-case": "error",
12+
"eqeqeq": ["error", "always", { "null": "ignore" }],
13+
"guard-for-in": "error",
14+
"max-len": ["warn", { "code": 140 }],
15+
"no-bitwise": "error",
16+
"no-caller": "error",
17+
"no-cond-assign": "error",
18+
"no-console": ["warn", { "allow": ["warn", "error"] }],
19+
"no-debugger": "error",
20+
"no-empty": "error",
21+
"no-eval": "error",
22+
"no-fallthrough": "error",
23+
"no-multiple-empty-lines": ["error", { "max": 1 }],
24+
"no-new-wrappers": "error",
25+
"no-redeclare": "off",
26+
"no-trailing-spaces": "error",
27+
"no-var": "error",
28+
"quotes": ["error", "single", { "avoidEscape": true }],
29+
"radix": "error",
30+
"semi": ["error", "always"],
31+
"@typescript-eslint/no-redeclare": "error",
32+
"@typescript-eslint/no-require-imports": "error",
33+
"@typescript-eslint/no-shadow": "error",
34+
"@typescript-eslint/no-unused-expressions": "warn",
35+
"@typescript-eslint/no-use-before-define": "error",
36+
"@typescript-eslint/no-var-requires": "error"
37+
},
38+
"overrides": [
39+
{
40+
"files": ["test/**/*.ts"],
41+
"rules": {
42+
"@typescript-eslint/no-unused-expressions": "off"
43+
}
44+
}
45+
],
46+
"ignorePatterns": ["out/**", "node_modules/**", ".vscode-test/**"]
47+
}

.github/workflows/ci.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
lint:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v6
13+
- uses: actions/setup-node@v6
14+
with:
15+
node-version: '22'
16+
cache: 'yarn'
17+
- name: Install dependencies
18+
run: yarn install --frozen-lockfile
19+
- name: Lint
20+
run: yarn lint
21+
22+
test:
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v6
26+
- uses: actions/setup-node@v6
27+
with:
28+
node-version: '22'
29+
cache: 'yarn'
30+
- name: Install dependencies
31+
run: yarn install --frozen-lockfile
32+
- name: Compile TypeScript
33+
run: yarn run vscode:prepublish
34+
- name: Run tests
35+
run: xvfb-run -a yarn test

package.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"vscode:prepublish": "tsc -p ./",
2626
"format": "tsfmt -r src/*",
2727
"compile": "tsc -watch -p ./",
28-
"postinstall": "node ./node_modules/vscode/bin/install",
29-
"test": "node ./node_modules/vscode/bin/test"
28+
"lint": "eslint 'src/**/*.ts' 'test/**/*.ts'",
29+
"test": "node ./out/test/runTests"
3030
},
3131
"contributes": {
3232
"languages": [
@@ -72,15 +72,19 @@
7272
}
7373
},
7474
"devDependencies": {
75-
"@types/chai": "^4.2.9",
76-
"@types/mocha": "^5.2.6",
77-
"@types/node": "^13.7.7",
78-
"chai": "^4.2.0",
79-
"mocha": "^6.0.2",
80-
"proxyquire": "^2.1.0",
81-
"sinon": "^7.3.0",
82-
"tslint": "^5.1.0",
83-
"typescript": "^3.8.3",
84-
"vscode": "^1.1.0"
75+
"@typescript-eslint/eslint-plugin": "^8.0.0",
76+
"@typescript-eslint/parser": "^8.0.0",
77+
"@types/chai": "^4.3.0",
78+
"@types/mocha": "^10.0.0",
79+
"@types/node": "^22.0.0",
80+
"@types/sinon": "^17.0.0",
81+
"@types/vscode": "^1.32.0",
82+
"@vscode/test-electron": "^2.0.0",
83+
"chai": "^4.4.0",
84+
"eslint": "^8.57.0",
85+
"mocha": "^10.0.0",
86+
"proxyquire": "^2.1.3",
87+
"sinon": "^19.0.0",
88+
"typescript": "^5.0.0"
8589
}
8690
}

src/configuration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export const getConfig: () => PackwerkConfig = () => {
1515
const conf = vs.workspace.getConfiguration('ruby.packwerk');
1616
let executable = conf.get('executable', 'bin/packwerk check');
1717

18-
console.debug(`[DEBUG] Parsing config, found executable '${executable}'`)
18+
// eslint-disable-next-line no-console
19+
console.debug(`[DEBUG] Parsing config, found executable '${executable}'`);
1920

2021
return {
2122
executable,

src/outputParser.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ export function parseOutput(str: string): PackwerkOutput {
1010

1111
let arr: RegExpExecArray;
1212
while ((arr = regex.exec(str)) !== null) {
13-
console.log("[DEBUG] Parsed regular expression", arr)
13+
// eslint-disable-next-line no-console
14+
console.log('[DEBUG] Parsed regular expression', arr);
1415
const file = arr[1];
1516
const line = Number(arr[2]);
1617
const column = Number(arr[3]);
1718
const message = arr[4].trim();
1819
const symbol = arr[5];
1920

20-
if (!files.has(file)) files.set(file, { path: file, violations: [] });
21+
if (!files.has(file)) { files.set(file, { path: file, violations: [] }); }
2122

2223
files.get(file)!.violations.push({
2324
message,

src/packwerk.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,18 @@ export class Packwerk {
4545
const fileName = document.fileName;
4646
const uri = document.uri;
4747
let currentPath = getCurrentPath(fileName);
48-
let relativeFileName = fileName.replace(currentPath + '/', '')
48+
let relativeFileName = fileName.replace(currentPath + '/', '');
4949

5050
let onDidExec = (error: Error, stdout: string, stderr: string) => {
51-
console.debug(`[DEBUG] Finished running command, in onDidExec`)
52-
console.debug(`[DEBUG] Error, stderr`, error, stderr)
51+
// eslint-disable-next-line no-console
52+
console.debug('[DEBUG] Finished running command, in onDidExec');
53+
// eslint-disable-next-line no-console
54+
console.debug('[DEBUG] Error, stderr', error, stderr);
5355
this.reportError(error, stderr);
5456
let packwerk = this.parse(stdout);
5557
if (packwerk === undefined || packwerk === null) {
56-
console.debug(`[DEBUG] packwerk is undefined or null, returning from onDidExec`)
58+
// eslint-disable-next-line no-console
59+
console.debug('[DEBUG] packwerk is undefined or null, returning from onDidExec');
5760
return;
5861
}
5962

@@ -76,7 +79,8 @@ export class Packwerk {
7679
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
7780

7881
const message = decolorizedMessage;
79-
console.debug(`[DEBUG] Adding vscode.Diagnostic:`, { range, message })
82+
// eslint-disable-next-line no-console
83+
console.debug('[DEBUG] Adding vscode.Diagnostic:', { range, message });
8084
const diagnostic = new vscode.Diagnostic(
8185
range,
8286
message,
@@ -130,8 +134,9 @@ export class Packwerk {
130134
options: cp.ExecOptions,
131135
cb: (err: Error, stdout: string, stderr: string) => void
132136
): cp.ChildProcess {
133-
let command = `${this.config.executable} ${fileName}`
134-
console.debug(`[DEBUG] Running command ${command}`)
137+
let command = `${this.config.executable} ${fileName}`;
138+
// eslint-disable-next-line no-console
139+
console.debug(`[DEBUG] Running command ${command}`);
135140

136141
let child = cp.exec(command, options, cb);
137142
child.stdin.write(fileContents); // why do we need this?
@@ -142,9 +147,11 @@ export class Packwerk {
142147
private parse(output: string): PackwerkOutput | null {
143148
let packwerk: PackwerkOutput;
144149
if (output.length < 1) {
145-
console.debug(`[DEBUG] Output is ${output}`)
150+
// eslint-disable-next-line no-console
151+
console.debug(`[DEBUG] Output is ${output}`);
146152
let message = `command ${this.config.executable} returns empty output! please check configuration.`;
147-
console.debug(`[DEBUG] ${message}`)
153+
// eslint-disable-next-line no-console
154+
console.debug(`[DEBUG] ${message}`);
148155
// For now, we do not show this error message. There are lots of reasons why this could fail, so
149156
// we turn it off so as to not bother the user
150157
// vscode.window.showWarningMessage(message);
@@ -176,11 +183,15 @@ export class Packwerk {
176183
);
177184
return true;
178185
} else if (error && (<any>error).code === 127 && this.config.showWarnings) {
179-
console.debug('[DEBUG] Showing error with code 127', stderr)
186+
// TODO: likely redundant; the same stderr is already surfaced via showWarningMessage below
187+
// eslint-disable-next-line no-console
188+
console.debug('[DEBUG] Showing error with code 127', stderr);
180189
vscode.window.showWarningMessage(stderr);
181190
return true;
182191
} else if (errorOutput.length > 0 && this.config.showWarnings) {
183-
console.debug('[DEBUG] Showing error with errorOutput.length > 0', stderr)
192+
// TODO: likely redundant; the same stderr is already surfaced via showWarningMessage below
193+
// eslint-disable-next-line no-console
194+
console.debug('[DEBUG] Showing error with errorOutput.length > 0', stderr);
184195
vscode.window.showWarningMessage(stderr);
185196
return true;
186197
}

src/taskQueue.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ export class TaskQueue {
9696
let uriString = uri.toString(true);
9797
this.tasks.forEach((task) => {
9898
if (task.uri.toString(true) === uriString) {
99-
console.debug(`[DEBUG] Canceling existing task for ${task.uri}`)
99+
// eslint-disable-next-line no-console
100+
console.debug(`[DEBUG] Canceling existing task for ${task.uri}`);
100101
task.cancel();
101102
}
102103
});

test/configuration.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ vsStub.workspace.getConfiguration = (
2020
};
2121

2222
return {
23-
get: <T>(section: string, defaultValue: T): T =>
24-
defaultConfig[section] || defaultValue,
23+
get: <T>(key: string, defaultValue: T): T =>
24+
defaultConfig[key] || defaultValue,
2525
};
2626
};
2727

test/index.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
1-
import * as testRunner from 'vscode/lib/testrunner';
1+
import * as fs from 'fs';
2+
import * as Mocha from 'mocha';
3+
import * as path from 'path';
24

3-
// see https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
4-
testRunner.configure({
5-
reporter: 'spec',
6-
ui: 'bdd',
7-
useColors: true,
8-
});
5+
export function run(): Promise<void> {
6+
const mocha = new Mocha({
7+
color: true,
8+
ui: 'bdd',
9+
});
910

10-
module.exports = testRunner;
11+
const testsRoot = path.resolve(__dirname, '.');
12+
const files = fs
13+
.readdirSync(testsRoot)
14+
.filter((f) => f.endsWith('.js') && f !== 'index.js' && f !== 'runTests.js');
15+
16+
files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
17+
18+
return new Promise((resolve, reject) => {
19+
try {
20+
mocha.run((failures) => {
21+
if (failures > 0) {
22+
reject(new Error(`${failures} tests failed.`));
23+
} else {
24+
resolve();
25+
}
26+
});
27+
} catch (err) {
28+
reject(err);
29+
}
30+
});
31+
}

test/runTests.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as path from 'path';
2+
import { runTests } from '@vscode/test-electron';
3+
4+
async function main(): Promise<void> {
5+
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
6+
const extensionTestsPath = path.resolve(__dirname, './index');
7+
8+
await runTests({ extensionDevelopmentPath, extensionTestsPath });
9+
}
10+
11+
main().catch((err) => {
12+
console.error(err);
13+
process.exit(1);
14+
});

0 commit comments

Comments
 (0)