@omni-oss/create-jobs 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
  All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
3
3
 
4
4
  - - -
5
+ ## @omni-oss/create-jobs-v0.1.5 - 2026-02-09
6
+ #### Bug Fixes
7
+ - (**@omni-oss/create-jobs**) support sanitizing artifact names - (1ed9932) - Clarence Manuel
8
+
9
+ - - -
10
+
5
11
  ## @omni-oss/create-jobs-v0.1.4 - 2026-02-08
6
12
  #### Bug Fixes
7
13
  - (**@omni-oss/create-jobs**) update comments - (b67cc92) - Clarence Manuel
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env bun
2
- "use strict";const o=require("node:fs/promises"),i=require("@commander-js/extra-typings"),r=require("./schemas-DxSZaHue.js"),l=new i.Command;l.argument("<input>","The input file to read from.").option("-o, --output <output>","The output file to write to.").action(async(n,t)=>{const u=await o.readFile(n,"utf-8"),a=JSON.parse(u),e=r.TaskResultArraySchema.safeParse(a);if(e.success){const c=e.data,s=r.createJobs(c);t.output?await o.writeFile(t.output,JSON.stringify(s,null,2)):console.log(s)}else console.error(e.error),process.exit(1)}).parseAsync();
2
+ "use strict";const o=require("node:fs/promises"),i=require("@commander-js/extra-typings"),r=require("./schemas-BCY99Jil.js"),l=new i.Command;l.argument("<input>","The input file to read from.").option("-o, --output <output>","The output file to write to.").action(async(n,t)=>{const u=await o.readFile(n,"utf-8"),a=JSON.parse(u),e=r.TaskResultArraySchema.safeParse(a);if(e.success){const c=e.data,s=r.createJobs(c);t.output?await o.writeFile(t.output,JSON.stringify(s,null,2)):console.log(s)}else console.error(e.error),process.exit(1)}).parseAsync();
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  import s from "node:fs/promises";
3
3
  import { Command as u } from "@commander-js/extra-typings";
4
- import { T as c, c as l } from "./schemas-DGmCKN3O.mjs";
4
+ import { T as c, c as l } from "./schemas-BNiWDmJf.mjs";
5
5
  const p = new u();
6
6
  p.argument("<input>", "The input file to read from.").option("-o, --output <output>", "The output file to write to.").action(async (r, e) => {
7
7
  const a = await s.readFile(r, "utf-8"), n = JSON.parse(a), t = c.safeParse(n);
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./schemas-DxSZaHue.js");exports.TaskResultArraySchema=e.TaskResultArraySchema;exports.TaskResultSchema=e.TaskResultSchema;exports.createJobs=e.createJobs;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./schemas-BCY99Jil.js");exports.TaskResultArraySchema=e.TaskResultArraySchema;exports.TaskResultSchema=e.TaskResultSchema;exports.createJobs=e.createJobs;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { T as e, a as r, c } from "./schemas-DGmCKN3O.mjs";
1
+ import { T as e, a as r, c } from "./schemas-BNiWDmJf.mjs";
2
2
  export {
3
3
  e as TaskResultArraySchema,
4
4
  r as TaskResultSchema,
@@ -0,0 +1 @@
1
+ "use strict";const c=require("node:path"),e=require("zod");function h(s){const a={test:{rust:[],typescript:[]},build:{rust:[],typescript:[]},publish:{npm:[],rust_github:[]}};for(const t of s){if(t.status==="skipped")continue;const r=t.task;r.task_name==="test"&&(t.details.meta?.language==="rust"&&a.test.rust.push(i(t)),t.details.meta?.language==="typescript"&&a.test.typescript.push(i(t))),r.task_name==="build"&&(t.details.meta?.language==="rust"&&a.build.rust.push(i(t)),t.details.meta?.language==="typescript"&&a.build.typescript.push(i(t))),r.task_name==="publish"&&t.details.meta?.release?.npm&&a.publish.npm.push(i(t)),t.details.meta?.release?.github&&t.details.meta?.language==="rust"&&a.publish.rust_github.push(i(t))}return a}function i(s){const a=[],t=[];if(s.details.output_files&&s.details.output_files.length>0)for(const r of s.details.output_files){const n=c.resolve(s.task.project_dir,r);u(s.task.project_dir,n)?t.push(n):a.push(n)}return{task_name:s.task.task_name,project_name:s.task.project_name,artifacts:{project:{name:`project-${o(s.task.project_name)}__${o(s.task.task_name)}`,files:t,files_count:t.length},workspace:{name:`workspace-${o(s.task.project_name)}__${o(s.task.task_name)}`,files:a,files_count:a.length}},project_dir:s.task.project_dir,meta:s.details.meta??{}}}function u(s,a){const t=c.relative(s,a);return t&&!t.startsWith("..")&&!c.isAbsolute(t)}function o(s){let a=s.replace(/[/\\?%*:|"<> \x00-\x1f]/g,"_");return a=a.replace(/[.\s]+$/,""),/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(a)&&(a+="_"),a||"unsaved_file"}const b=e.z.object({secs:e.z.number().int().nonnegative().describe("The number of whole seconds elapsed."),nanos:e.z.number().int().nonnegative().describe("The number of nanoseconds elapsed.")}),m=e.z.object({runner:e.z.string().describe("The runner to use for the target.")}),f=e.z.object({npm:e.z.boolean().optional().describe("Whether to publish to npm."),github:e.z.boolean().optional().describe("Whether to publish to github.")}),g=e.z.object({type:e.z.string().optional().describe("The type of project (e.g., library, service, application)."),language:e.z.string().optional().describe("The primary language of the project."),targets:e.z.record(e.z.string(),m).optional().describe("The targets to build."),release:f.optional()}),l=e.z.object({meta:g.optional(),output_files:e.z.array(e.z.string()).optional().describe("The output files generated.")}),d=e.z.object({task_name:e.z.string().describe("The short name of the task (e.g., 'test', 'build')."),task_command:e.z.string().describe("The command executed for the task."),project_name:e.z.string().describe("The name of the project."),project_dir:e.z.string().describe("The absolute directory path of the project."),full_task_name:e.z.string().describe("The fully qualified task name (e.g., 'omni_utils#test')."),dependencies:e.z.array(e.z.string()).describe("A list of dependent task names."),enabled:e.z.boolean().or(e.z.string()).optional().describe("Whether the task is enabled by configuration. Either a boolean or a tera template string that evaluates to a boolean."),interactive:e.z.boolean().describe("Whether the task is interactive."),persistent:e.z.boolean().describe("Whether the task is persistent.")}),k=e.z.object({status:e.z.literal("completed"),hash:e.z.string().describe("The task's content hash (Base64 encoded string). Used for caching."),task:d,exit_code:e.z.number().int().describe("The exit code of the executed command (typically 0 for success)."),elapsed:b.describe("The duration the task took to execute."),cache_hit:e.z.boolean().describe("Indicates if the result was pulled from cache."),details:l}),z=e.z.object({status:e.z.literal("errored"),task:d,error:e.z.string().describe("The error message."),details:l}),_=e.z.object({status:e.z.literal("skipped"),task:d,skip_reason:e.z.string().describe("The reason the task was skipped (e.g., 'disabled')."),details:l}),p=e.z.discriminatedUnion("status",[k,_,z]).describe("Schema for a single task execution result (completed or skipped)."),j=e.z.array(p).describe("An array of task execution results.");exports.TaskResultArraySchema=j;exports.TaskResultSchema=p;exports.createJobs=h;
@@ -1,6 +1,6 @@
1
- import n from "node:path";
1
+ import c from "node:path";
2
2
  import { z as e } from "zod";
3
- function T(s) {
3
+ function y(s) {
4
4
  const a = {
5
5
  test: {
6
6
  rust: [],
@@ -27,20 +27,20 @@ function i(s) {
27
27
  const a = [], t = [];
28
28
  if (s.details.output_files && s.details.output_files.length > 0)
29
29
  for (const r of s.details.output_files) {
30
- const o = n.resolve(s.task.project_dir, r);
31
- p(s.task.project_dir, o) ? t.push(o) : a.push(o);
30
+ const n = c.resolve(s.task.project_dir, r);
31
+ d(s.task.project_dir, n) ? t.push(n) : a.push(n);
32
32
  }
33
33
  return {
34
34
  task_name: s.task.task_name,
35
35
  project_name: s.task.project_name,
36
36
  artifacts: {
37
37
  project: {
38
- name: `project-${s.task.project_name}__${s.task.task_name}`,
38
+ name: `project-${o(s.task.project_name)}__${o(s.task.task_name)}`,
39
39
  files: t,
40
40
  files_count: t.length
41
41
  },
42
42
  workspace: {
43
- name: `workspace-${s.task.project_name}__${s.task.task_name}`,
43
+ name: `workspace-${o(s.task.project_name)}__${o(s.task.task_name)}`,
44
44
  files: a,
45
45
  files_count: a.length
46
46
  }
@@ -49,27 +49,31 @@ function i(s) {
49
49
  meta: s.details.meta ?? {}
50
50
  };
51
51
  }
52
- function p(s, a) {
53
- const t = n.relative(s, a);
54
- return t && !t.startsWith("..") && !n.isAbsolute(t);
52
+ function d(s, a) {
53
+ const t = c.relative(s, a);
54
+ return t && !t.startsWith("..") && !c.isAbsolute(t);
55
55
  }
56
- const d = e.object({
56
+ function o(s) {
57
+ let a = s.replace(/[/\\?%*:|"<> \x00-\x1f]/g, "_");
58
+ return a = a.replace(/[.\s]+$/, ""), /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(a) && (a += "_"), a || "unsaved_file";
59
+ }
60
+ const h = e.object({
57
61
  secs: e.number().int().nonnegative().describe("The number of whole seconds elapsed."),
58
62
  nanos: e.number().int().nonnegative().describe("The number of nanoseconds elapsed.")
59
- }), h = e.object({
60
- runner: e.string().describe("The runner to use for the target.")
61
63
  }), u = e.object({
64
+ runner: e.string().describe("The runner to use for the target.")
65
+ }), b = e.object({
62
66
  npm: e.boolean().optional().describe("Whether to publish to npm."),
63
67
  github: e.boolean().optional().describe("Whether to publish to github.")
64
- }), b = e.object({
68
+ }), m = e.object({
65
69
  type: e.string().optional().describe("The type of project (e.g., library, service, application)."),
66
70
  language: e.string().optional().describe("The primary language of the project."),
67
- targets: e.record(e.string(), h).optional().describe("The targets to build."),
68
- release: u.optional()
69
- }), c = e.object({
70
- meta: b.optional(),
71
- output_files: e.array(e.string()).optional().describe("The output files generated.")
71
+ targets: e.record(e.string(), u).optional().describe("The targets to build."),
72
+ release: b.optional()
72
73
  }), l = e.object({
74
+ meta: m.optional(),
75
+ output_files: e.array(e.string()).optional().describe("The output files generated.")
76
+ }), p = e.object({
73
77
  task_name: e.string().describe("The short name of the task (e.g., 'test', 'build')."),
74
78
  task_command: e.string().describe("The command executed for the task."),
75
79
  project_name: e.string().describe("The name of the project."),
@@ -81,37 +85,37 @@ const d = e.object({
81
85
  ),
82
86
  interactive: e.boolean().describe("Whether the task is interactive."),
83
87
  persistent: e.boolean().describe("Whether the task is persistent.")
84
- }), m = e.object({
88
+ }), f = e.object({
85
89
  status: e.literal("completed"),
86
90
  hash: e.string().describe(
87
91
  "The task's content hash (Base64 encoded string). Used for caching."
88
92
  ),
89
- task: l,
93
+ task: p,
90
94
  exit_code: e.number().int().describe(
91
95
  "The exit code of the executed command (typically 0 for success)."
92
96
  ),
93
- elapsed: d.describe("The duration the task took to execute."),
97
+ elapsed: h.describe("The duration the task took to execute."),
94
98
  cache_hit: e.boolean().describe("Indicates if the result was pulled from cache."),
95
- details: c
96
- }), f = e.object({
99
+ details: l
100
+ }), g = e.object({
97
101
  status: e.literal("errored"),
98
- task: l,
102
+ task: p,
99
103
  error: e.string().describe("The error message."),
100
- details: c
101
- }), g = e.object({
104
+ details: l
105
+ }), k = e.object({
102
106
  status: e.literal("skipped"),
103
- task: l,
107
+ task: p,
104
108
  skip_reason: e.string().describe("The reason the task was skipped (e.g., 'disabled')."),
105
- details: c
106
- }), k = e.discriminatedUnion("status", [
107
- m,
108
- g,
109
- f
109
+ details: l
110
+ }), _ = e.discriminatedUnion("status", [
111
+ f,
112
+ k,
113
+ g
110
114
  ]).describe(
111
115
  "Schema for a single task execution result (completed or skipped)."
112
- ), y = e.array(k).describe("An array of task execution results.");
116
+ ), S = e.array(_).describe("An array of task execution results.");
113
117
  export {
114
- y as T,
115
- k as a,
116
- T as c
118
+ S as T,
119
+ _ as a,
120
+ y as c
117
121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omni-oss/create-jobs",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "bin": "./dist/create-jobs.mjs",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -182,4 +182,38 @@ describe("createJobs", () => {
182
182
  },
183
183
  });
184
184
  });
185
+
186
+ it("should sanitize the project name and task name in artifact names", () => {
187
+ const results: any[] = [
188
+ {
189
+ status: "success",
190
+ task: {
191
+ task_name: "test",
192
+ project_name: "@project/name",
193
+ project_dir: "/mnt/c/Users/user/project",
194
+ },
195
+ details: {
196
+ meta: { language: "rust" },
197
+ output_files: [],
198
+ },
199
+ },
200
+ ];
201
+
202
+ const jobs = createJobs(results);
203
+
204
+ expect(jobs.test.rust[0]).toMatchObject({
205
+ project_name: "@project/name",
206
+ task_name: "test",
207
+ artifacts: {
208
+ project: {
209
+ name: "project-@project_name__test",
210
+ files: [],
211
+ },
212
+ workspace: {
213
+ name: "workspace-@project_name__test",
214
+ files: [],
215
+ },
216
+ },
217
+ });
218
+ });
185
219
  });
@@ -117,12 +117,12 @@ function jobFromResult(result: TaskResult): Job {
117
117
  project_name: result.task.project_name,
118
118
  artifacts: {
119
119
  project: {
120
- name: `project-${result.task.project_name}__${result.task.task_name}`,
120
+ name: `project-${toPathSafeString(result.task.project_name)}__${toPathSafeString(result.task.task_name)}`,
121
121
  files: projectArtifacts,
122
122
  files_count: projectArtifacts.length,
123
123
  },
124
124
  workspace: {
125
- name: `workspace-${result.task.project_name}__${result.task.task_name}`,
125
+ name: `workspace-${toPathSafeString(result.task.project_name)}__${toPathSafeString(result.task.task_name)}`,
126
126
  files: workspaceArtifacts,
127
127
  files_count: workspaceArtifacts.length,
128
128
  },
@@ -145,3 +145,23 @@ function isPathInside(parent: string, child: string) {
145
145
  // it means the child is outside the parent.
146
146
  return relative && !relative.startsWith("..") && !path.isAbsolute(relative);
147
147
  }
148
+
149
+ function toPathSafeString(str: string): string {
150
+ // 1. Replace illegal characters: / \ ? % * : | " < >
151
+ // Also includes control characters (0-31) which are illegal on Windows
152
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: false
153
+ let safeStr = str.replace(/[/\\?%*:|"<> \x00-\x1f]/g, "_");
154
+
155
+ // 2. Trim trailing dots and spaces (illegal on Windows filenames)
156
+ safeStr = safeStr.replace(/[.\s]+$/, "");
157
+
158
+ // 3. Handle Windows Reserved Names (CON, PRN, AUX, NUL, COM1-9, LPT1-9)
159
+ // These cannot be filenames even if they have no extension.
160
+ const reservedNames = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i;
161
+ if (reservedNames.test(safeStr)) {
162
+ safeStr += "_";
163
+ }
164
+
165
+ // 4. Fallback for empty strings or strings that became empty after stripping
166
+ return safeStr || "unsaved_file";
167
+ }
@@ -1 +0,0 @@
1
- "use strict";const n=require("node:path"),e=require("zod");function d(s){const a={test:{rust:[],typescript:[]},build:{rust:[],typescript:[]},publish:{npm:[],rust_github:[]}};for(const t of s){if(t.status==="skipped")continue;const r=t.task;r.task_name==="test"&&(t.details.meta?.language==="rust"&&a.test.rust.push(i(t)),t.details.meta?.language==="typescript"&&a.test.typescript.push(i(t))),r.task_name==="build"&&(t.details.meta?.language==="rust"&&a.build.rust.push(i(t)),t.details.meta?.language==="typescript"&&a.build.typescript.push(i(t))),r.task_name==="publish"&&t.details.meta?.release?.npm&&a.publish.npm.push(i(t)),t.details.meta?.release?.github&&t.details.meta?.language==="rust"&&a.publish.rust_github.push(i(t))}return a}function i(s){const a=[],t=[];if(s.details.output_files&&s.details.output_files.length>0)for(const r of s.details.output_files){const o=n.resolve(s.task.project_dir,r);h(s.task.project_dir,o)?t.push(o):a.push(o)}return{task_name:s.task.task_name,project_name:s.task.project_name,artifacts:{project:{name:`project-${s.task.project_name}__${s.task.task_name}`,files:t,files_count:t.length},workspace:{name:`workspace-${s.task.project_name}__${s.task.task_name}`,files:a,files_count:a.length}},project_dir:s.task.project_dir,meta:s.details.meta??{}}}function h(s,a){const t=n.relative(s,a);return t&&!t.startsWith("..")&&!n.isAbsolute(t)}const u=e.z.object({secs:e.z.number().int().nonnegative().describe("The number of whole seconds elapsed."),nanos:e.z.number().int().nonnegative().describe("The number of nanoseconds elapsed.")}),b=e.z.object({runner:e.z.string().describe("The runner to use for the target.")}),m=e.z.object({npm:e.z.boolean().optional().describe("Whether to publish to npm."),github:e.z.boolean().optional().describe("Whether to publish to github.")}),g=e.z.object({type:e.z.string().optional().describe("The type of project (e.g., library, service, application)."),language:e.z.string().optional().describe("The primary language of the project."),targets:e.z.record(e.z.string(),b).optional().describe("The targets to build."),release:m.optional()}),c=e.z.object({meta:g.optional(),output_files:e.z.array(e.z.string()).optional().describe("The output files generated.")}),l=e.z.object({task_name:e.z.string().describe("The short name of the task (e.g., 'test', 'build')."),task_command:e.z.string().describe("The command executed for the task."),project_name:e.z.string().describe("The name of the project."),project_dir:e.z.string().describe("The absolute directory path of the project."),full_task_name:e.z.string().describe("The fully qualified task name (e.g., 'omni_utils#test')."),dependencies:e.z.array(e.z.string()).describe("A list of dependent task names."),enabled:e.z.boolean().or(e.z.string()).optional().describe("Whether the task is enabled by configuration. Either a boolean or a tera template string that evaluates to a boolean."),interactive:e.z.boolean().describe("Whether the task is interactive."),persistent:e.z.boolean().describe("Whether the task is persistent.")}),k=e.z.object({status:e.z.literal("completed"),hash:e.z.string().describe("The task's content hash (Base64 encoded string). Used for caching."),task:l,exit_code:e.z.number().int().describe("The exit code of the executed command (typically 0 for success)."),elapsed:u.describe("The duration the task took to execute."),cache_hit:e.z.boolean().describe("Indicates if the result was pulled from cache."),details:c}),f=e.z.object({status:e.z.literal("errored"),task:l,error:e.z.string().describe("The error message."),details:c}),z=e.z.object({status:e.z.literal("skipped"),task:l,skip_reason:e.z.string().describe("The reason the task was skipped (e.g., 'disabled')."),details:c}),p=e.z.discriminatedUnion("status",[k,z,f]).describe("Schema for a single task execution result (completed or skipped)."),_=e.z.array(p).describe("An array of task execution results.");exports.TaskResultArraySchema=_;exports.TaskResultSchema=p;exports.createJobs=d;