chore: move captureGitInfo back into config (#34961)
This commit is contained in:
parent
53f38f19a4
commit
e033e5aa11
|
@ -36,6 +36,26 @@ export default defineConfig({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## property: TestConfig.captureGitInfo
|
||||||
|
* since: v1.51
|
||||||
|
- type: ?<[Object]>
|
||||||
|
- `commit` ?<boolean> Whether to capture commit information such as hash, author, timestamp.
|
||||||
|
- `diff` ?<boolean> Whether to capture commit diff.
|
||||||
|
|
||||||
|
* These settings control whether git information is captured and stored in the config [`property: TestConfig.metadata`].
|
||||||
|
* The structure of the git commit metadata is subject to change.
|
||||||
|
* Default values for these settings depend on the environment. When tests run as a part of CI where it is safe to obtain git information, the default value is true, false otherwise.
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```js title="playwright.config.ts"
|
||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
captureGitInfo: { commit: true, diff: true }
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## property: TestConfig.expect
|
## property: TestConfig.expect
|
||||||
* since: v1.10
|
* since: v1.10
|
||||||
- type: ?<[Object]>
|
- type: ?<[Object]>
|
||||||
|
@ -239,11 +259,6 @@ export default defineConfig({
|
||||||
|
|
||||||
Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as key-value pairs, and JSON report will include metadata serialized as json.
|
Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as key-value pairs, and JSON report will include metadata serialized as json.
|
||||||
|
|
||||||
* Providing `gitCommit: 'generate'` property will populate it with the git commit details.
|
|
||||||
* Providing `gitDiff: 'generate'` property will populate it with the git diff details.
|
|
||||||
|
|
||||||
On selected CI providers, both will be generated automatically. Specifying values will prevent the automatic generation.
|
|
||||||
|
|
||||||
**Usage**
|
**Usage**
|
||||||
|
|
||||||
```js title="playwright.config.ts"
|
```js title="playwright.config.ts"
|
||||||
|
|
|
@ -48,6 +48,7 @@ export class FullConfigInternal {
|
||||||
readonly plugins: TestRunnerPluginRegistration[];
|
readonly plugins: TestRunnerPluginRegistration[];
|
||||||
readonly projects: FullProjectInternal[] = [];
|
readonly projects: FullProjectInternal[] = [];
|
||||||
readonly singleTSConfigPath?: string;
|
readonly singleTSConfigPath?: string;
|
||||||
|
readonly captureGitInfo: Config['captureGitInfo'];
|
||||||
cliArgs: string[] = [];
|
cliArgs: string[] = [];
|
||||||
cliGrep: string | undefined;
|
cliGrep: string | undefined;
|
||||||
cliGrepInvert: string | undefined;
|
cliGrepInvert: string | undefined;
|
||||||
|
@ -77,6 +78,7 @@ export class FullConfigInternal {
|
||||||
const privateConfiguration = (userConfig as any)['@playwright/test'];
|
const privateConfiguration = (userConfig as any)['@playwright/test'];
|
||||||
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
|
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
|
||||||
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
|
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
|
||||||
|
this.captureGitInfo = userConfig.captureGitInfo;
|
||||||
|
|
||||||
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
|
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
|
||||||
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
|
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
|
||||||
|
|
|
@ -42,12 +42,6 @@ export type CIInfo = {
|
||||||
branch?: string;
|
branch?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserMetadataWithCommitInfo = {
|
|
||||||
ci?: CIInfo;
|
|
||||||
gitCommit?: GitCommitInfo | 'generate';
|
|
||||||
gitDiff?: string | 'generate';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MetadataWithCommitInfo = {
|
export type MetadataWithCommitInfo = {
|
||||||
ci?: CIInfo;
|
ci?: CIInfo;
|
||||||
gitCommit?: GitCommitInfo;
|
gitCommit?: GitCommitInfo;
|
||||||
|
|
|
@ -21,30 +21,26 @@ import { spawnAsync } from 'playwright-core/lib/utils';
|
||||||
import type { TestRunnerPlugin } from './';
|
import type { TestRunnerPlugin } from './';
|
||||||
import type { FullConfig } from '../../types/testReporter';
|
import type { FullConfig } from '../../types/testReporter';
|
||||||
import type { FullConfigInternal } from '../common/config';
|
import type { FullConfigInternal } from '../common/config';
|
||||||
import type { GitCommitInfo, CIInfo, UserMetadataWithCommitInfo } from '../isomorphic/types';
|
import type { GitCommitInfo, CIInfo, MetadataWithCommitInfo } from '../isomorphic/types';
|
||||||
|
|
||||||
const GIT_OPERATIONS_TIMEOUT_MS = 3000;
|
const GIT_OPERATIONS_TIMEOUT_MS = 3000;
|
||||||
|
|
||||||
export const addGitCommitInfoPlugin = (fullConfig: FullConfigInternal) => {
|
export const addGitCommitInfoPlugin = (fullConfig: FullConfigInternal) => {
|
||||||
fullConfig.plugins.push({ factory: gitCommitInfoPlugin });
|
fullConfig.plugins.push({ factory: gitCommitInfoPlugin.bind(null, fullConfig) });
|
||||||
};
|
};
|
||||||
|
|
||||||
type GitCommitInfoPluginOptions = {
|
const gitCommitInfoPlugin = (fullConfig: FullConfigInternal): TestRunnerPlugin => {
|
||||||
directory?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const gitCommitInfoPlugin = (options?: GitCommitInfoPluginOptions): TestRunnerPlugin => {
|
|
||||||
return {
|
return {
|
||||||
name: 'playwright:git-commit-info',
|
name: 'playwright:git-commit-info',
|
||||||
|
|
||||||
setup: async (config: FullConfig, configDir: string) => {
|
setup: async (config: FullConfig, configDir: string) => {
|
||||||
const metadata = config.metadata as UserMetadataWithCommitInfo;
|
const metadata = config.metadata as MetadataWithCommitInfo;
|
||||||
const ci = await ciInfo();
|
const ci = await ciInfo();
|
||||||
if (!metadata.ci && ci)
|
if (!metadata.ci && ci)
|
||||||
metadata.ci = ci;
|
metadata.ci = ci;
|
||||||
|
|
||||||
if ((ci && !metadata.gitCommit) || metadata.gitCommit === 'generate') {
|
if (fullConfig.captureGitInfo?.commit || (fullConfig.captureGitInfo?.commit === undefined && ci)) {
|
||||||
const git = await gitCommitInfo(options?.directory || configDir).catch(e => {
|
const git = await gitCommitInfo(configDir).catch(e => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('Failed to get git commit info', e);
|
console.error('Failed to get git commit info', e);
|
||||||
});
|
});
|
||||||
|
@ -52,8 +48,8 @@ export const gitCommitInfoPlugin = (options?: GitCommitInfoPluginOptions): TestR
|
||||||
metadata.gitCommit = git;
|
metadata.gitCommit = git;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ci && !metadata.gitDiff) || metadata.gitDiff === 'generate') {
|
if (fullConfig.captureGitInfo?.diff || (fullConfig.captureGitInfo?.diff === undefined && ci)) {
|
||||||
const diffResult = await gitDiff(options?.directory || configDir, ci).catch(e => {
|
const diffResult = await gitDiff(configDir, ci).catch(e => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error('Failed to get git diff', e);
|
console.error('Failed to get git diff', e);
|
||||||
});
|
});
|
||||||
|
|
|
@ -959,6 +959,37 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
|
||||||
external?: Array<string>;
|
external?: Array<string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* - These settings control whether git information is captured and stored in the config
|
||||||
|
* [testConfig.metadata](https://playwright.dev/docs/api/class-testconfig#test-config-metadata).
|
||||||
|
* - The structure of the git commit metadata is not documented and is a subject to change.
|
||||||
|
* - Default values for these settings depend on the environment. When tests run as a part of CI where it is safe to
|
||||||
|
* obtain git information, the default value is true, false otherise.
|
||||||
|
*
|
||||||
|
* **Usage**
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // playwright.config.ts
|
||||||
|
* import { defineConfig } from '@playwright/test';
|
||||||
|
*
|
||||||
|
* export default defineConfig({
|
||||||
|
* captureGitInfo: { commit: true, diff: true }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
captureGitInfo?: {
|
||||||
|
/**
|
||||||
|
* Whether to capture commit information such as hash, author, timestamp.
|
||||||
|
*/
|
||||||
|
commit?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to capture commit diff.
|
||||||
|
*/
|
||||||
|
diff?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
* Configuration for the `expect` assertion library. Learn more about [various timeouts](https://playwright.dev/docs/test-timeouts).
|
||||||
*
|
*
|
||||||
|
@ -1284,11 +1315,6 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
|
||||||
/**
|
/**
|
||||||
* Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as
|
* Metadata contains key-value pairs to be included in the report. For example, HTML report will display it as
|
||||||
* key-value pairs, and JSON report will include metadata serialized as json.
|
* key-value pairs, and JSON report will include metadata serialized as json.
|
||||||
* - Providing `gitCommit: 'generate'` property will populate it with the git commit details.
|
|
||||||
* - Providing `gitDiff: 'generate'` property will populate it with the git diff details.
|
|
||||||
*
|
|
||||||
* On selected CI providers, both will be generated automatically. Specifying values will prevent the automatic
|
|
||||||
* generation.
|
|
||||||
*
|
*
|
||||||
* **Usage**
|
* **Usage**
|
||||||
*
|
*
|
||||||
|
|
|
@ -1187,7 +1187,43 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should include metadata with gitCommit', async ({ runInlineTest, writeFiles, showReport, page }) => {
|
test('should include commit metadata w/ captureGitInfo', async ({ runInlineTest, writeFiles, showReport, page }) => {
|
||||||
|
const files = {
|
||||||
|
'uncommitted.txt': `uncommitted file`,
|
||||||
|
'playwright.config.ts': `
|
||||||
|
export default {
|
||||||
|
captureGitInfo: { commit: true },
|
||||||
|
metadata: { foo: 'value1', bar: { prop: 'value2' }, baz: ['value3', 123] }
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'example.spec.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('sample', async ({}) => { expect(2).toBe(2); });
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
const baseDir = await writeFiles(files);
|
||||||
|
await initGitRepo(baseDir);
|
||||||
|
|
||||||
|
const result = await runInlineTest(files, { reporter: 'dot,html' }, {
|
||||||
|
PLAYWRIGHT_HTML_OPEN: 'never',
|
||||||
|
});
|
||||||
|
|
||||||
|
await showReport();
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
await page.getByRole('button', { name: 'Metadata' }).click();
|
||||||
|
await expect(page.locator('.metadata-view')).toMatchAriaSnapshot(`
|
||||||
|
- list:
|
||||||
|
- listitem: "chore(html): make this test look nice"
|
||||||
|
- listitem: /William <shakespeare@example\\.local>/
|
||||||
|
- list:
|
||||||
|
- listitem: "foo : value1"
|
||||||
|
- listitem: "bar : {\\"prop\\":\\"value2\\"}"
|
||||||
|
- listitem: "baz : [\\"value3\\",123]"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should include commit metadata w/ CI', async ({ runInlineTest, writeFiles, showReport, page }) => {
|
||||||
const files = {
|
const files = {
|
||||||
'uncommitted.txt': `uncommitted file`,
|
'uncommitted.txt': `uncommitted file`,
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
|
@ -1201,21 +1237,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
const baseDir = await writeFiles(files);
|
const baseDir = await writeFiles(files);
|
||||||
|
await initGitRepo(baseDir);
|
||||||
const execGit = async (args: string[]) => {
|
|
||||||
const { code, stdout, stderr } = await spawnAsync('git', args, { stdio: 'pipe', cwd: baseDir });
|
|
||||||
if (!!code)
|
|
||||||
throw new Error(`Non-zero exit of:\n$ git ${args.join(' ')}\nConsole:\nstdout:\n${stdout}\n\nstderr:\n${stderr}\n\n`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
await execGit(['init']);
|
|
||||||
await execGit(['config', '--local', 'user.email', 'shakespeare@example.local']);
|
|
||||||
await execGit(['config', '--local', 'user.name', 'William']);
|
|
||||||
await execGit(['add', 'playwright.config.ts']);
|
|
||||||
await execGit(['commit', '-m', 'init']);
|
|
||||||
await execGit(['add', '*.ts']);
|
|
||||||
await execGit(['commit', '-m', 'chore(html): make this test look nice']);
|
|
||||||
|
|
||||||
const result = await runInlineTest(files, { reporter: 'dot,html' }, {
|
const result = await runInlineTest(files, { reporter: 'dot,html' }, {
|
||||||
PLAYWRIGHT_HTML_OPEN: 'never',
|
PLAYWRIGHT_HTML_OPEN: 'never',
|
||||||
|
@ -1241,7 +1263,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should include metadata on GHA', async ({ runInlineTest, writeFiles, showReport, page }) => {
|
test('should include PR metadata on GHA', async ({ runInlineTest, writeFiles, showReport, page }) => {
|
||||||
const files = {
|
const files = {
|
||||||
'uncommitted.txt': `uncommitted file`,
|
'uncommitted.txt': `uncommitted file`,
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
|
@ -1255,21 +1277,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
const baseDir = await writeFiles(files);
|
const baseDir = await writeFiles(files);
|
||||||
|
await initGitRepo(baseDir);
|
||||||
const execGit = async (args: string[]) => {
|
|
||||||
const { code, stdout, stderr } = await spawnAsync('git', args, { stdio: 'pipe', cwd: baseDir });
|
|
||||||
if (!!code)
|
|
||||||
throw new Error(`Non-zero exit of:\n$ git ${args.join(' ')}\nConsole:\nstdout:\n${stdout}\n\nstderr:\n${stderr}\n\n`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
await execGit(['init']);
|
|
||||||
await execGit(['config', '--local', 'user.email', 'shakespeare@example.local']);
|
|
||||||
await execGit(['config', '--local', 'user.name', 'William']);
|
|
||||||
await execGit(['add', 'playwright.config.ts']);
|
|
||||||
await execGit(['commit', '-m', 'init']);
|
|
||||||
await execGit(['add', '*.ts']);
|
|
||||||
await execGit(['commit', '-m', 'chore(html): make this test look nice']);
|
|
||||||
|
|
||||||
const eventPath = path.join(baseDir, 'event.json');
|
const eventPath = path.join(baseDir, 'event.json');
|
||||||
await fs.promises.writeFile(eventPath, JSON.stringify({
|
await fs.promises.writeFile(eventPath, JSON.stringify({
|
||||||
|
@ -1306,7 +1314,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not include git metadata w/o gitCommit', async ({ runInlineTest, showReport, page }) => {
|
test('should not include git metadata w/o CI', async ({ runInlineTest, showReport, page }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
export default {};
|
export default {};
|
||||||
|
@ -2780,21 +2788,7 @@ for (const useIntermediateMergeReport of [true, false] as const) {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
const baseDir = await writeFiles(files);
|
const baseDir = await writeFiles(files);
|
||||||
|
await initGitRepo(baseDir);
|
||||||
const execGit = async (args: string[]) => {
|
|
||||||
const { code, stdout, stderr } = await spawnAsync('git', args, { stdio: 'pipe', cwd: baseDir });
|
|
||||||
if (!!code)
|
|
||||||
throw new Error(`Non-zero exit of:\n$ git ${args.join(' ')}\nConsole:\nstdout:\n${stdout}\n\nstderr:\n${stderr}\n\n`);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
await execGit(['init']);
|
|
||||||
await execGit(['config', '--local', 'user.email', 'shakespeare@example.local']);
|
|
||||||
await execGit(['config', '--local', 'user.name', 'William']);
|
|
||||||
await execGit(['add', 'playwright.config.ts']);
|
|
||||||
await execGit(['commit', '-m', 'init']);
|
|
||||||
await execGit(['add', '*.ts']);
|
|
||||||
await execGit(['commit', '-m', 'chore(html): make this test look nice']);
|
|
||||||
|
|
||||||
const result = await runInlineTest(files, { reporter: 'dot,html' }, {
|
const result = await runInlineTest(files, { reporter: 'dot,html' }, {
|
||||||
PLAYWRIGHT_HTML_OPEN: 'never',
|
PLAYWRIGHT_HTML_OPEN: 'never',
|
||||||
|
@ -2831,3 +2825,20 @@ function readAllFromStream(stream: NodeJS.ReadableStream): Promise<Buffer> {
|
||||||
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initGitRepo(baseDir) {
|
||||||
|
const execGit = async (args: string[]) => {
|
||||||
|
const { code, stdout, stderr } = await spawnAsync('git', args, { stdio: 'pipe', cwd: baseDir });
|
||||||
|
if (!!code)
|
||||||
|
throw new Error(`Non-zero exit of:\n$ git ${args.join(' ')}\nConsole:\nstdout:\n${stdout}\n\nstderr:\n${stderr}\n\n`);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
await execGit(['init']);
|
||||||
|
await execGit(['config', '--local', 'user.email', 'shakespeare@example.local']);
|
||||||
|
await execGit(['config', '--local', 'user.name', 'William']);
|
||||||
|
await execGit(['add', 'playwright.config.ts']);
|
||||||
|
await execGit(['commit', '-m', 'init']);
|
||||||
|
await execGit(['add', '*.ts']);
|
||||||
|
await execGit(['commit', '-m', 'chore(html): make this test look nice']);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue