Skip to content

feat(ci): skip persist.format args if defaults already configured #1042

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 31, 2025
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
16 changes: 16 additions & 0 deletions e2e/ci-e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable functional/immutable-data */

const originalCI = process.env['CI'];

export function setup() {
// package is expected to run in CI environment
process.env['CI'] = 'true';
}

export function teardown() {
if (originalCI === undefined) {
delete process.env['CI'];
} else {
process.env['CI'] = originalCI;
}
}
3 changes: 2 additions & 1 deletion e2e/ci-e2e/tsconfig.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"vitest.e2e.config.ts",
"tests/**/*.e2e.test.ts",
"tests/**/*.d.ts",
"mocks/**/*.ts"
"mocks/**/*.ts",
"global-setup.ts"
]
}
1 change: 1 addition & 0 deletions e2e/ci-e2e/vitest.e2e.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineConfig({
},
environment: 'node',
include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
globalSetup: './global-setup.ts',
setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'],
},
});
14 changes: 7 additions & 7 deletions packages/ci/src/lib/cli/commands/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { DEFAULT_PERSIST_FORMAT } from '@code-pushup/models';
import { executeProcess, isVerbose } from '@code-pushup/utils';
import type { CommandContext } from '../context.js';

export async function runCollect({
bin,
config,
directory,
observer,
}: CommandContext): Promise<void> {
export async function runCollect(
{ bin, config, directory, observer }: CommandContext,
{ hasFormats }: { hasFormats: boolean },
): Promise<void> {
await executeProcess({
command: bin,
args: [
...(isVerbose() ? ['--verbose'] : []),
...(config ? [`--config=${config}`] : []),
...DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`),
...(hasFormats
? []
: DEFAULT_PERSIST_FORMAT.map(format => `--persist.format=${format}`)),
],
cwd: directory,
observer,
Expand Down
65 changes: 45 additions & 20 deletions packages/ci/src/lib/run-monorepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
type RunEnv,
checkPrintConfig,
compareReports,
hasDefaultPersistFormats,
loadCachedBaseReport,
printPersistConfig,
runInBaseBranch,
Expand Down Expand Up @@ -116,24 +117,35 @@ async function runProjectsInBulk(
`Running on ${projects.length} projects in bulk (parallel: ${settings.parallel})`,
);

await collectMany(runManyCommand, env);

const currProjectReports = await asyncSequential(
projects,
async (project): Promise<ProjectReport> => {
const ctx = createCommandContext(settings, project);
const config = await printPersistConfig(ctx);
const reports = await saveOutputFiles({
project,
type: 'current',
files: persistedFilesFromConfig(config, ctx),
settings,
});
return { project, reports, config, ctx };
},
);
const currProjectConfigs = await asyncSequential(projects, async project => {
const ctx = createCommandContext(settings, project);
const config = await printPersistConfig(ctx);
return { project, config, ctx };
});
const hasFormats = allProjectsHaveDefaultPersistFormats(currProjectConfigs);
logger.debug(
`Loaded ${currProjectReports.length} persist configs by running print-config command for each project`,
[
`Loaded ${currProjectConfigs.length} persist configs by running print-config command for each project.`,
hasFormats
? 'Every project has default persist formats.'
: 'Not all projects have default persist formats.',
].join(' '),
);

await collectMany(runManyCommand, env, { hasFormats });

const currProjectReports = await Promise.all(
currProjectConfigs.map(
async ({ project, config, ctx }): Promise<ProjectReport> => {
const reports = await saveOutputFiles({
project,
type: 'current',
files: persistedFilesFromConfig(config, ctx),
settings,
});
return { project, reports, config, ctx };
},
),
);

if (base == null) {
Expand Down Expand Up @@ -248,10 +260,12 @@ async function collectPreviousReports(
}

if (onlyProjects.length > 0) {
const hasFormats =
allProjectsHaveDefaultPersistFormats(validProjectConfigs);
logger.info(
`Collecting previous reports for ${onlyProjects.length} projects`,
);
await collectMany(runManyCommand, env, onlyProjects);
await collectMany(runManyCommand, env, { hasFormats, onlyProjects });
}

const projectFiles = validProjectConfigs.map(args =>
Expand Down Expand Up @@ -281,16 +295,21 @@ async function savePreviousProjectReport(args: {
async function collectMany(
runManyCommand: RunManyCommand,
env: RunEnv,
onlyProjects?: string[],
options: {
hasFormats: boolean;
onlyProjects?: string[];
},
): Promise<void> {
const { settings } = env;
const { hasFormats, onlyProjects } = options;

const command = await runManyCommand(onlyProjects);
const ctx: CommandContext = {
...createCommandContext(settings, null),
bin: command,
};

await runCollect(ctx);
await runCollect(ctx, { hasFormats });

const countText = onlyProjects
? `${onlyProjects.length} previous`
Expand All @@ -299,3 +318,9 @@ async function collectMany(
`Collected ${countText} reports using command \`${command}\``,
);
}

export function allProjectsHaveDefaultPersistFormats(
projects: { config: Pick<CoreConfig, 'persist'> }[],
): boolean {
return projects.every(({ config }) => hasDefaultPersistFormats(config));
}
21 changes: 18 additions & 3 deletions packages/ci/src/lib/run-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/* eslint-disable max-lines */
import { readFile } from 'node:fs/promises';
import type { SimpleGit } from 'simple-git';
import type { CoreConfig, Report, ReportsDiff } from '@code-pushup/models';
import {
type CoreConfig,
DEFAULT_PERSIST_FORMAT,
type Report,
type ReportsDiff,
} from '@code-pushup/models';
import {
removeUndefinedAndEmptyProps,
stringifyError,
Expand Down Expand Up @@ -112,7 +117,7 @@ export async function runOnProject(
`Loaded persist config from print-config command - ${JSON.stringify(config.persist)}`,
);

await runCollect(ctx);
await runCollect(ctx, { hasFormats: hasDefaultPersistFormats(config) });
const currReport = await saveReportFiles({
project,
type: 'current',
Expand Down Expand Up @@ -221,7 +226,7 @@ export async function collectPreviousReport(
return null;
}

await runCollect(ctx);
await runCollect(ctx, { hasFormats: hasDefaultPersistFormats(config) });
const report = await saveReportFiles({
project,
type: 'previous',
Expand Down Expand Up @@ -329,6 +334,16 @@ export async function printPersistConfig(
return parsePersistConfig(json);
}

export function hasDefaultPersistFormats(
config: Pick<CoreConfig, 'persist'>,
): boolean {
const formats = config.persist?.format;
return (
formats == null ||
DEFAULT_PERSIST_FORMAT.every(format => formats.includes(format))
);
}

export async function findNewIssues(
args: CompareReportsArgs & { diffFiles: OutputFiles },
): Promise<SourceFileIssue[]> {
Expand Down
16 changes: 8 additions & 8 deletions packages/ci/src/lib/run.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -334,7 +334,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand All @@ -346,7 +346,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(4, {
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -418,7 +418,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenNthCalledWith(2, {
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: workDir,
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -605,7 +605,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: runMany,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -763,7 +763,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: runMany,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -951,7 +951,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down Expand Up @@ -1120,7 +1120,7 @@ describe('runInCI', () => {
} satisfies utils.ProcessConfig);
expect(utils.executeProcess).toHaveBeenCalledWith({
command: options.bin,
args: ['--persist.format=json', '--persist.format=md'],
args: [],
cwd: expect.stringContaining(workDir),
observer: expectedObserver,
} satisfies utils.ProcessConfig);
Expand Down
Loading