Skip to content
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