Skip to content

feat(models): add generic artifact generation to enable caching #1023

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
18 changes: 18 additions & 0 deletions packages/models/docs/models-reference.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Code PushUp models reference

## ArtifactGenerationCommand

_Union of the following possible types:_

- `string` (_min length: 1_)
- _Object with properties:_<ul><li>`command`: `string` (_min length: 1_) - Generate artifact files</li><li>`args`: `Array<string>`</li></ul>

## AuditDetails

Detailed information
Expand Down Expand Up @@ -1227,6 +1234,17 @@ _Object containing the following properties:_

_All properties are optional._

## PluginArtifactOptions

_Object containing the following properties:_

| Property | Type |
| :------------------------- | :------------------------------------------------------ |
| `generateArtifactsCommand` | [ArtifactGenerationCommand](#artifactgenerationcommand) |
| **`artifactsPaths`** (\*) | `string` _or_ `Array<string>` (_min: 1_) |

_(\*) Required._

## PluginConfig

_Object containing the following properties:_
Expand Down
4 changes: 4 additions & 0 deletions packages/models/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,7 @@ export {
type Tree,
} from './lib/tree.js';
export { uploadConfigSchema, type UploadConfig } from './lib/upload-config.js';
export {
artifactGenerationCommandSchema,
pluginArtifactOptionsSchema,
} from './lib/configuration.js';
19 changes: 19 additions & 0 deletions packages/models/src/lib/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { z } from 'zod';

/**
* Generic schema for a tool command configuration, reusable across plugins.
*/
export const artifactGenerationCommandSchema = z.union([
z.string({ description: 'Generate artifact files' }).min(1),
z.object({
command: z.string({ description: 'Generate artifact files' }).min(1),
args: z.array(z.string()).optional(),
}),
]);

export const pluginArtifactOptionsSchema = z.object({
generateArtifactsCommand: artifactGenerationCommandSchema.optional(),
artifactsPaths: z.union([z.string(), z.array(z.string()).min(1)]),
});

export type PluginArtifactOptions = z.infer<typeof pluginArtifactOptionsSchema>;
127 changes: 127 additions & 0 deletions packages/models/src/lib/configuration.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { describe, expect, it } from 'vitest';
import {
artifactGenerationCommandSchema,
pluginArtifactOptionsSchema,
} from './configuration.js';

describe('artifactGenerationCommandSchema', () => {
it('should validate a command with required fields', () => {
const data = { command: 'npx' };
expect(artifactGenerationCommandSchema.safeParse(data)).toStrictEqual({
success: true,
data: { command: 'npx' },
});
});

it('should validate a command with args', () => {
const data = { command: 'npx', args: ['eslint', 'src/'] };
expect(artifactGenerationCommandSchema.safeParse(data)).toStrictEqual({
success: true,
data: { command: 'npx', args: ['eslint', 'src/'] },
});
});

it('should fail if command is missing', () => {
const data = { args: ['eslint', 'src/'] };
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
});

it('should fail if command is empty', () => {
const data = { command: '' };
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
});

it('should fail if args is not an array of strings', () => {
const data = { command: 'npx', args: [123, true] };
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
});
});

describe('pluginArtifactOptionsSchema', () => {
it('should validate with only artifactsPaths as string', () => {
const data = { artifactsPaths: 'dist/report.json' };
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
success: true,
data: {
artifactsPaths: 'dist/report.json',
},
});
});

it('should validate with artifactsPaths as array of strings', () => {
const data = { artifactsPaths: ['dist/report.json', 'dist/summary.json'] };
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
success: true,
data: {
artifactsPaths: ['dist/report.json', 'dist/summary.json'],
},
});
});

it('should fail if artifactsPaths is an empty array', () => {
const data = { artifactsPaths: [] };
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});

it('should validate with generateArtifactsCommand and artifactsPaths', () => {
const data = {
generateArtifactsCommand: { command: 'npm', args: ['run', 'build'] },
artifactsPaths: ['dist/report.json'],
};
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
success: true,
data: {
generateArtifactsCommand: { command: 'npm', args: ['run', 'build'] },
artifactsPaths: ['dist/report.json'],
},
});
});

it('should fail if artifactsPaths is missing', () => {
const data = { generateArtifactsCommand: { command: 'npm' } };
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});

it('should fail if artifactsPaths is not string or array of strings', () => {
const data = { artifactsPaths: 123 };
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});

it('should fail if generateArtifactsCommand is invalid', () => {
const data = {
generateArtifactsCommand: { command: '' },
artifactsPaths: 'dist/report.json',
};
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});

it('should validate with generateArtifactsCommand as a string', () => {
const data = {
generateArtifactsCommand: 'yarn test --coverage',
artifactsPaths: 'coverage/lcov.info',
};
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
success: true,
data: {
generateArtifactsCommand: 'yarn test --coverage',
artifactsPaths: 'coverage/lcov.info',
},
});
});

it('should fail if generateArtifactsCommand is an empty string', () => {
const data = {
generateArtifactsCommand: '',
artifactsPaths: 'coverage/lcov.info',
};
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});

it('should fail if generateArtifactsCommand is a number', () => {
const data = {
generateArtifactsCommand: 123,
artifactsPaths: 'coverage/lcov.info',
};
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
});
});
Loading