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
2 changes: 1 addition & 1 deletion .github/workflows/rslint-ecosystem-ci-from-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
prepare-binding:
name: Prepare Rslint Binding
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 90
outputs:
commit-sha: ${{ steps.prepare.outputs.commit-sha }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rslint-ecosystem-ci-from-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
prepare-binding:
name: Prepare Rslint Binding
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 90
outputs:
commit-sha: ${{ steps.prepare.outputs.commit-sha }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rslint-ecosystem-ci-selected.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
prepare-binding:
name: Prepare Rslint Binding
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 90
outputs:
commit-sha: ${{ steps.prepare.outputs.commit-sha }}
steps:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rstest-ecosystem-ci-from-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
execute-selected-suite:
runs-on: ubuntu-latest
if: "inputs.suite != '-'"
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down Expand Up @@ -115,6 +116,7 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
name: execute-all (${{ matrix.suite }})
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rstest-ecosystem-ci-from-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
execute-selected-suite:
runs-on: ubuntu-latest
if: "inputs.suite != '-'"
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down Expand Up @@ -112,6 +113,7 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
name: execute-all (${{ matrix.suite }})
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/rstest-ecosystem-ci-selected.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ jobs:
execute-selected-suite:
runs-on: ubuntu-latest
if: "inputs.suite != '-'"
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down Expand Up @@ -121,6 +122,7 @@ jobs:
fail-fast: false
runs-on: ${{ matrix.os }}
name: execute-all (${{ matrix.suite }})
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: ./.github/actions/build-rstest
Expand Down
18 changes: 1 addition & 17 deletions tests/rslint/rstack-editor.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1 @@
import type { RunOptions } from '../../types';
import { runInRepo } from '../../utils';

// `test:unit` runs the editor's unit tests, which load `@rslint/core` in the
// lint worker, and `lint` runs `rs lint --type-check`, which type-checks the
// editor against `@rslint/core` (the worker imports its `config-loader` and
// `eslint-plugin` modules) and uses that core as the linter engine.
// E2E tests are intentionally excluded because they need VS Code and a
// display server.
export async function test(options: RunOptions) {
await runInRepo({
...options,
repo: 'rstackjs/rstack-editor',
branch: process.env.RSTACK_EDITOR ?? 'main',
test: ['test:unit', 'lint'],
});
}
export { test } from '../shared/rstack-editor';
16 changes: 1 addition & 15 deletions tests/rstest/rstack-editor.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1 @@
import type { RunOptions } from '../../types';
import { runInRepo } from '../../utils';

// `test:unit` runs the editor's unit tests on Rstest, and `lint` runs
// `rs lint --type-check`, which type-checks the code against `@rstest/core`.
// E2E tests are intentionally excluded because they need VS Code and a
// display server.
export async function test(options: RunOptions) {
await runInRepo({
...options,
repo: 'rstackjs/rstack-editor',
branch: 'main',
test: ['test:unit', 'lint'],
});
}
export { test } from '../shared/rstack-editor';
69 changes: 69 additions & 0 deletions tests/shared/rstack-editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import assert from 'node:assert';
import path from 'node:path';
import type { RunOptions } from '../../types';
import {
execa,
getMonorepoPackages,
getRslintPackages,
runInRepo,
} from '../../utils';

const REPO = 'rstackjs/rstack-editor';

// `test:unit` runs the editor's unit tests on the stack in question, `lint`
// runs `rs lint --type-check`, and `build` produces `packages/vscode/dist`,
// which the E2E extension host loads.
//
// The E2E fixtures install published packages, so the unreleased stack build
// is injected through `RSTACK_E2E_TOOLCHAIN_OVERRIDES` (tarballs packed from
// the stack checkout), never through eco-ci's consumer overrides. Rslint needs
// both `@rslint/core` and its host `@rslint/native-<tuple>`: core resolves its
// binary through `require.resolve('@rslint/native-<tuple>/bin')`, so
// overriding core alone would leave the published binary in place. Rstest
// needs only `@rstest/core`, found by package name through the cached
// monorepo scan, so neither suite hardcodes the upstream layout.
async function toolchainOverrides(options: RunOptions): Promise<string> {
if (options.stack === 'rslint') {
return getRslintPackages(options.stackPath)
.map(({ name, directory }) => `${name}=${directory}`)
.join(',');
Comment thread
fi3ework marked this conversation as resolved.
Resolved
}
const core = (await getMonorepoPackages('rstest')).find(
({ name }) => name === '@rstest/core',
);
assert(core, `@rstest/core not found in ${options.stackPath}`);
return `@rstest/core=${core.directory}`;
}

// The VS Code download is cached beside the checkout because runInRepo runs
// `git clean -fdxq` in it and would otherwise wipe `.vscode-test/`. Only the
// rslint suite has ever taken its branch from `RSTACK_EDITOR`.
export async function test(options: RunOptions) {
assert(
options.stack === 'rstest' || options.stack === 'rslint',
`rstack-editor E2E does not support the ${options.stack} stack`,
);
const isRstest = options.stack === 'rstest';
await runInRepo({
...options,
repo: REPO,
branch: isRstest ? 'main' : (process.env.RSTACK_EDITOR ?? 'main'),
build: 'build',
test: [
'test:unit',
'lint',
async ({ dir }) => {
await execa(`node e2e/run.mjs ${isRstest ? 'rstest' : 'smoke lint'}`, {
cwd: path.join(dir, 'packages/vscode'),
env: {
RSTACK_E2E_TOOLCHAIN_OVERRIDES: await toolchainOverrides(options),
VSCODE_TEST_CACHE_PATH: path.join(
options.workspace,
'.vscode-test',
),
},
});
},
],
});
}
4 changes: 3 additions & 1 deletion types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export interface RunOptions {
suiteCommit?: string;
}

export type Task = string | (() => Promise<any>);
// Function tasks receive the checkout `runInRepo` resolved, so a task can work
// inside the consumer without re-deriving the directory naming rule.
export type Task = string | ((context: { dir: string }) => Promise<any>);

export interface CommandOptions {
stack?: Stack;
Expand Down
26 changes: 16 additions & 10 deletions utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,16 @@ export const execa = async (cmd: string, options?: ExecaOptions) => {
console.log(`${cwd} $> ${cmd}`);
}

// `options.env` would replace the environment `setupEnvironment` built
// (`CI`, `ECOSYSTEM_CI`, `NODE_OPTIONS`, …) rather than merge into it —
// execa's `extendEnv` only re-adds `process.env`. Fold caller additions into
// the snapshot; every other option keeps its precedence over the defaults.
const { env: extraEnv, ...rest } = options ?? {};
const proc = execaCommand(cmd, {
env,
env: { ...env, ...extraEnv },
cwd,
stdio: 'pipe',
...options,
...rest,
});
proc.stdin?.pipe(process.stdin);
proc.stdout?.pipe(process.stdout);
Expand Down Expand Up @@ -323,6 +328,7 @@ export async function setupRepo(options: RepoOptions) {
function toCommand(
task: Task | Task[] | void,
agent: Agent,
dir: string,
): ((scripts: any) => Promise<any>) | void {
return async (scripts: any) => {
const tasks = Array.isArray(task) ? task : [task];
Expand All @@ -345,7 +351,7 @@ function toCommand(
await $`${task}`;
}
} else if (typeof task === 'function') {
await task();
await task({ dir });
} else {
throw new Error(
`invalid task, expected string or function but got ${typeof task}: ${task}`,
Expand Down Expand Up @@ -402,7 +408,7 @@ export async function discoverMonorepoPackages(
});
}

async function getMonorepoPackages(stack: MonorepoStack) {
export async function getMonorepoPackages(stack: MonorepoStack) {
const cached = monorepoPackagesCache[stack];
if (cached) {
return cached;
Expand Down Expand Up @@ -679,12 +685,12 @@ export async function runInRepo(options: RunOptions & RepoOptions) {
);
}
const agent = options.agent;
const beforeInstallCommand = toCommand(beforeInstall, agent);
const afterInstallCommand = toCommand(afterInstall, agent);
const beforeBuildCommand = toCommand(beforeBuild, agent);
const beforeTestCommand = toCommand(beforeTest, agent);
const buildCommand = toCommand(build, agent);
const testCommand = toCommand(test, agent);
const beforeInstallCommand = toCommand(beforeInstall, agent, dir);
const afterInstallCommand = toCommand(afterInstall, agent, dir);
const beforeBuildCommand = toCommand(beforeBuild, agent, dir);
const beforeTestCommand = toCommand(beforeTest, agent, dir);
const buildCommand = toCommand(build, agent, dir);
const testCommand = toCommand(test, agent, dir);

const pkgFile = path.join(dir, 'package.json');
const pkg = JSON.parse(await fs.promises.readFile(pkgFile, 'utf-8'));
Expand Down
Loading