Skip to content
Open
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
9 changes: 9 additions & 0 deletions .github/actions/detect-changes/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ outputs:
copilot:
description: "'true' when the Copilot extension checks in extensions/copilot/ need to run."
value: ${{ steps.detect.outputs.copilot }}
unit-tests:
description: "'true' when the Electron, node.js and browser unit tests need to run."
value: ${{ steps.detect.outputs.unit-tests }}
browser-integration:
description: "'true' when the browser integration and smoke tests need to run."
value: ${{ steps.detect.outputs.browser-integration }}
product-tests:
description: "'true' when the Electron integration, Electron smoke and remote tests need to run."
value: ${{ steps.detect.outputs.product-tests }}

runs:
using: composite
Expand Down
63 changes: 63 additions & 0 deletions .github/actions/detect-changes/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,56 @@ const rules: readonly IChangeRule[] = [
},
];

/**
* Core test jobs that run unless every changed path is one the tests cannot read. Any other path,
* including a new kind of file, runs the jobs.
*/
interface ICoreTestRule {
/** Name of the action output that reports whether the jobs need to run. */
readonly output: string;
/** Whether the jobs cannot be affected by a change to the path. */
readonly canSkip: (path: string) => boolean;
}

/** Markdown outside the sources, tests and extensions, which use Markdown files as test inputs. */
function isDocumentation(path: string): boolean {
return path.endsWith('.md') && !/^(src|test|extensions)\//.test(path);
}

/** The Rust crates, which the core test jobs neither build nor run. */
function isRustCrate(path: string): boolean {
return path.startsWith('cli/') || path.startsWith('copilot_shim/');
}

/**
* Built-in extensions whose files the core unit tests read: the component fixtures load the themes and
* these grammars. build/lib/test/detectChanges.test.ts fails when a test starts reading another extension.
*/
const extensionsReadByUnitTests = new Set(['css', 'html', 'javascript', 'json', 'typescript-basics']);

function isExtensionNotReadByUnitTests(path: string): boolean {
const name = /^extensions\/([^/]+)\//.exec(path)?.[1];
return name !== undefined && !name.startsWith('theme-') && !extensionsReadByUnitTests.has(name);
}

const coreTestRules: readonly ICoreTestRule[] = [
{
// Electron, node.js and browser unit tests load only the core sources and their test fixtures.
output: 'unit-tests',
canSkip: path => isDocumentation(path) || isRustCrate(path) || isExtensionNotReadByUnitTests(path),
},
{
// The browser integration and smoke tests do not load the Copilot extension.
output: 'browser-integration',
canSkip: path => isDocumentation(path) || isRustCrate(path) || path.startsWith('extensions/copilot/'),
},
{
// The Electron integration, Electron smoke and remote tests exercise the built-in extensions.
output: 'product-tests',
canSkip: path => isDocumentation(path) || isRustCrate(path),
},
];

function matchesAny(path: string, patterns: readonly string[]): boolean {
return patterns.some(pattern => pattern.endsWith('/') ? path.startsWith(pattern) : path === pattern);
}
Expand Down Expand Up @@ -135,4 +185,17 @@ export async function detectChanges(github: IGitHub, context: IContext, core: IC
core.info(`${rule.output}: ${affected ? 'run' : 'skip'} (${reason})`);
core.setOutput(rule.output, affected ? 'true' : 'false');
}

for (const rule of coreTestRules) {
const changedPath = paths?.find(path => !rule.canSkip(path));
// An empty file list carries no evidence that the checks are unaffected.
const affected = paths === undefined || paths.length === 0 || changedPath !== undefined;
const reason = paths === undefined ? 'changed files unavailable'
: paths.length === 0 ? 'no changed files reported'
: changedPath !== undefined ? `changed ${changedPath}`
: 'only changes the tests cannot read';

core.info(`${rule.output}: ${affected ? 'run' : 'skip'} (${reason})`);
core.setOutput(rule.output, affected ? 'true' : 'false');
}
}
2 changes: 1 addition & 1 deletion .github/skills/smoke-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The runner exits non-zero if any test fails, so a `0` exit code means every sele

### Sharding in PR CI

The GitHub PR workflows split the Electron smoke tests with a matrix (`shard: [1, 2]`) on the `<os>-electron-smoke-test-shards` jobs in `.github/workflows/pr.yml`, which pass `--shard` to the runner. They report as `<OS> (shard 1/2) / Electron-Smoke` and `<OS> (shard 2/2) / Electron-Smoke`. A matrix gate job, `electron-smoke-checks`, reports the required `<OS> / Electron-Smoke` checks and fails a platform's check if any of its shards did not succeed. To change the shard count, edit the matrix list. Near the top of each shard's `smoke-test-runner.log`, a `Running smoke test shard <index>/<total>` line lists the suites that shard ran.
The GitHub PR workflows split the Electron smoke tests with a matrix (`shard: [1, 2]`) on the `<os>-electron-smoke-test-shards` jobs in `.github/workflows/pr.yml`, which pass `--shard` to the runner. They report as `<OS> (shard 1/2) / Electron-Smoke` and `<OS> (shard 2/2) / Electron-Smoke`. A gate job, `required-checks`, reports the required `<OS> / Electron-Smoke` checks and fails a platform's check if any of its shards did not succeed. The shards are skipped, and the check passes, when the pull request only changes paths the smoke tests cannot read (see `.github/actions/detect-changes/detect.ts`). To change the shard count, edit the matrix list. Near the top of each shard's `smoke-test-runner.log`, a `Running smoke test shard <index>/<total>` line lists the suites that shard ran.

Some placement is coupled to the workflows, and `test/smoke/src/shard.ts` encodes it:

Expand Down
Loading