Skip to content

Commit ed01057

Browse files
AndriiSiutaAS
andauthored
feat(models): add generic artifact generation to enable caching (#1023)
Closes #1021 --------- Co-authored-by: AS <ASiuta_ext@mapal-os.com>
1 parent f4db136 commit ed01057

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed

packages/models/docs/models-reference.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Code PushUp models reference
22

3+
## ArtifactGenerationCommand
4+
5+
_Union of the following possible types:_
6+
7+
- `string` (_min length: 1_)
8+
- _Object with properties:_<ul><li>`command`: `string` (_min length: 1_) - Generate artifact files</li><li>`args`: `Array<string>`</li></ul>
9+
310
## AuditDetails
411

512
Detailed information
@@ -1227,6 +1234,17 @@ _Object containing the following properties:_
12271234

12281235
_All properties are optional._
12291236

1237+
## PluginArtifactOptions
1238+
1239+
_Object containing the following properties:_
1240+
1241+
| Property | Type |
1242+
| :------------------------- | :------------------------------------------------------ |
1243+
| `generateArtifactsCommand` | [ArtifactGenerationCommand](#artifactgenerationcommand) |
1244+
| **`artifactsPaths`** (\*) | `string` _or_ `Array<string>` (_min: 1_) |
1245+
1246+
_(\*) Required._
1247+
12301248
## PluginConfig
12311249

12321250
_Object containing the following properties:_

packages/models/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,7 @@ export {
134134
type Tree,
135135
} from './lib/tree.js';
136136
export { uploadConfigSchema, type UploadConfig } from './lib/upload-config.js';
137+
export {
138+
artifactGenerationCommandSchema,
139+
pluginArtifactOptionsSchema,
140+
} from './lib/configuration.js';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { z } from 'zod';
2+
3+
/**
4+
* Generic schema for a tool command configuration, reusable across plugins.
5+
*/
6+
export const artifactGenerationCommandSchema = z.union([
7+
z.string({ description: 'Generate artifact files' }).min(1),
8+
z.object({
9+
command: z.string({ description: 'Generate artifact files' }).min(1),
10+
args: z.array(z.string()).optional(),
11+
}),
12+
]);
13+
14+
export const pluginArtifactOptionsSchema = z.object({
15+
generateArtifactsCommand: artifactGenerationCommandSchema.optional(),
16+
artifactsPaths: z.union([z.string(), z.array(z.string()).min(1)]),
17+
});
18+
19+
export type PluginArtifactOptions = z.infer<typeof pluginArtifactOptionsSchema>;
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { describe, expect, it } from 'vitest';
2+
import {
3+
artifactGenerationCommandSchema,
4+
pluginArtifactOptionsSchema,
5+
} from './configuration.js';
6+
7+
describe('artifactGenerationCommandSchema', () => {
8+
it('should validate a command with required fields', () => {
9+
const data = { command: 'npx' };
10+
expect(artifactGenerationCommandSchema.safeParse(data)).toStrictEqual({
11+
success: true,
12+
data: { command: 'npx' },
13+
});
14+
});
15+
16+
it('should validate a command with args', () => {
17+
const data = { command: 'npx', args: ['eslint', 'src/'] };
18+
expect(artifactGenerationCommandSchema.safeParse(data)).toStrictEqual({
19+
success: true,
20+
data: { command: 'npx', args: ['eslint', 'src/'] },
21+
});
22+
});
23+
24+
it('should fail if command is missing', () => {
25+
const data = { args: ['eslint', 'src/'] };
26+
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
27+
});
28+
29+
it('should fail if command is empty', () => {
30+
const data = { command: '' };
31+
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
32+
});
33+
34+
it('should fail if args is not an array of strings', () => {
35+
const data = { command: 'npx', args: [123, true] };
36+
expect(artifactGenerationCommandSchema.safeParse(data).success).toBe(false);
37+
});
38+
});
39+
40+
describe('pluginArtifactOptionsSchema', () => {
41+
it('should validate with only artifactsPaths as string', () => {
42+
const data = { artifactsPaths: 'dist/report.json' };
43+
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
44+
success: true,
45+
data: {
46+
artifactsPaths: 'dist/report.json',
47+
},
48+
});
49+
});
50+
51+
it('should validate with artifactsPaths as array of strings', () => {
52+
const data = { artifactsPaths: ['dist/report.json', 'dist/summary.json'] };
53+
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
54+
success: true,
55+
data: {
56+
artifactsPaths: ['dist/report.json', 'dist/summary.json'],
57+
},
58+
});
59+
});
60+
61+
it('should fail if artifactsPaths is an empty array', () => {
62+
const data = { artifactsPaths: [] };
63+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
64+
});
65+
66+
it('should validate with generateArtifactsCommand and artifactsPaths', () => {
67+
const data = {
68+
generateArtifactsCommand: { command: 'npm', args: ['run', 'build'] },
69+
artifactsPaths: ['dist/report.json'],
70+
};
71+
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
72+
success: true,
73+
data: {
74+
generateArtifactsCommand: { command: 'npm', args: ['run', 'build'] },
75+
artifactsPaths: ['dist/report.json'],
76+
},
77+
});
78+
});
79+
80+
it('should fail if artifactsPaths is missing', () => {
81+
const data = { generateArtifactsCommand: { command: 'npm' } };
82+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
83+
});
84+
85+
it('should fail if artifactsPaths is not string or array of strings', () => {
86+
const data = { artifactsPaths: 123 };
87+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
88+
});
89+
90+
it('should fail if generateArtifactsCommand is invalid', () => {
91+
const data = {
92+
generateArtifactsCommand: { command: '' },
93+
artifactsPaths: 'dist/report.json',
94+
};
95+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
96+
});
97+
98+
it('should validate with generateArtifactsCommand as a string', () => {
99+
const data = {
100+
generateArtifactsCommand: 'yarn test --coverage',
101+
artifactsPaths: 'coverage/lcov.info',
102+
};
103+
expect(pluginArtifactOptionsSchema.safeParse(data)).toStrictEqual({
104+
success: true,
105+
data: {
106+
generateArtifactsCommand: 'yarn test --coverage',
107+
artifactsPaths: 'coverage/lcov.info',
108+
},
109+
});
110+
});
111+
112+
it('should fail if generateArtifactsCommand is an empty string', () => {
113+
const data = {
114+
generateArtifactsCommand: '',
115+
artifactsPaths: 'coverage/lcov.info',
116+
};
117+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
118+
});
119+
120+
it('should fail if generateArtifactsCommand is a number', () => {
121+
const data = {
122+
generateArtifactsCommand: 123,
123+
artifactsPaths: 'coverage/lcov.info',
124+
};
125+
expect(pluginArtifactOptionsSchema.safeParse(data).success).toBe(false);
126+
});
127+
});

0 commit comments

Comments
 (0)