@forgehive/forge-cli 0.2.10 → 0.2.11

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/dist/index.js CHANGED
@@ -7,9 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const minimist_1 = __importDefault(require("minimist"));
8
8
  const runner_1 = __importDefault(require("./runner"));
9
9
  const args = (0, minimist_1.default)(process.argv.slice(2));
10
- runner_1.default.handler(args).then(data => {
10
+ runner_1.default.handler(args).then((data) => {
11
+ const { silent, outcome, result } = data;
12
+ if (silent) {
13
+ return;
14
+ }
11
15
  console.log('===============================================');
12
- console.log('Outcome', data);
16
+ console.log(`Outcome: ${outcome}`);
17
+ console.log('===============================================');
18
+ console.log('Result', result);
13
19
  console.log('===============================================');
14
20
  }).catch((e) => {
15
21
  console.error(e);
package/dist/runner.js CHANGED
@@ -57,9 +57,10 @@ runner.load('auth:remove', remove_3.remove);
57
57
  runner.setHandler(async (data) => {
58
58
  const parsedArgs = runner.parseArguments(data);
59
59
  const { taskName, action, args } = parsedArgs;
60
- console.log('========================================');
60
+ console.log('===============================================');
61
61
  console.log(`Running: ${taskName} ${action ? action : ''} ${JSON.stringify(args)}`);
62
- console.log('========================================');
62
+ console.log('===============================================');
63
+ let silent = false;
63
64
  const task = runner.getTask(taskName);
64
65
  if (!task) {
65
66
  throw new Error(`Task "${taskName}" not found`);
@@ -111,6 +112,7 @@ runner.setHandler(async (data) => {
111
112
  descriptorName: action,
112
113
  uuid
113
114
  });
115
+ silent = true;
114
116
  }
115
117
  else if (taskName === 'auth:add') {
116
118
  const { apiKey, apiSecret, url } = args;
@@ -130,6 +132,7 @@ runner.setHandler(async (data) => {
130
132
  result = await task.run(args);
131
133
  }
132
134
  return {
135
+ silent,
133
136
  outcome: 'Success',
134
137
  taskName,
135
138
  result
@@ -1,6 +1,7 @@
1
1
  import { Profile } from '../types';
2
2
  interface FixtureData {
3
3
  name: string;
4
+ boundaries: Record<string, unknown>;
4
5
  [key: string]: unknown;
5
6
  }
6
7
  interface FixtureResponse {
@@ -17,10 +18,10 @@ export declare const download: import("@forgehive/task").TaskInstanceType<(argv:
17
18
  persistFixture: (filePath: string, data: FixtureData) => Promise<{
18
19
  path: string;
19
20
  }>;
20
- checkFileExists: (filePath: string) => Promise<boolean>;
21
21
  }>) => Promise<{
22
22
  status: string;
23
23
  path: string;
24
+ shortPath: string;
24
25
  }>, {
25
26
  loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
26
27
  loadConf: (args: {}) => Promise<Promise<import("../types").ForgeConf>>;
@@ -29,6 +30,5 @@ export declare const download: import("@forgehive/task").TaskInstanceType<(argv:
29
30
  persistFixture: (filePath: string, data: FixtureData) => Promise<{
30
31
  path: string;
31
32
  }>;
32
- checkFileExists: (filePath: string) => Promise<boolean>;
33
33
  }>;
34
34
  export {};
@@ -43,20 +43,12 @@ const boundaries = {
43
43
  return {
44
44
  path: filePath
45
45
  };
46
- },
47
- checkFileExists: async (filePath) => {
48
- try {
49
- await promises_1.default.access(filePath);
50
- return true;
51
- }
52
- catch {
53
- return false;
54
- }
55
46
  }
56
47
  };
57
- exports.download = (0, task_1.createTask)(schema, boundaries, async function ({ uuid }, { downloadFixture, getCwd, persistFixture, checkFileExists, loadCurrentProfile, loadConf }) {
48
+ exports.download = (0, task_1.createTask)(schema, boundaries, async function ({ uuid }, { downloadFixture, getCwd, persistFixture, loadCurrentProfile, loadConf }) {
58
49
  console.log('==================================================');
59
50
  console.log(`Attempting to download fixture with uuid: ${uuid}`);
51
+ console.log('==================================================');
60
52
  const profile = await loadCurrentProfile({});
61
53
  const cwd = await getCwd();
62
54
  const forge = await loadConf({});
@@ -73,34 +65,35 @@ exports.download = (0, task_1.createTask)(schema, boundaries, async function ({
73
65
  }
74
66
  throw new Error('Failed to download fixture');
75
67
  }
76
- // Extract task descriptor from the response
77
- const taskName = response.fixture.name;
68
+ const fixture = response.fixture;
69
+ const taskName = fixture.taskName;
78
70
  // Determine the output path using forge fixtures path and task descriptor
79
71
  const fixturesBasePath = forge.paths.fixtures || 'fixtures';
80
72
  const fixtureDir = path_1.default.join(fixturesBasePath, taskName);
81
73
  const fixturePath = path_1.default.join(fixtureDir, `${uuid}.json`);
82
74
  const filePath = path_1.default.resolve(cwd, fixturePath);
83
- console.log(`Fixture will be saved to: ${filePath}`);
84
- // Check if file already exists
85
- const fileExists = await checkFileExists(filePath);
86
- if (fileExists) {
87
- console.log(`Fixture will be updated at ${filePath}`);
88
- }
89
- console.log(`
90
- ==================================================
91
- Starting fixture download!
92
- Fixture UUID: ${uuid}
93
- Task Name: ${taskName}
94
- Saving to: ${filePath}
95
- ==================================================
96
- Replay with: forge task:replay --path ${filePath}
97
- ==================================================
98
- `);
99
75
  // Persist fixture to file
100
76
  await persistFixture(filePath, response.fixture);
77
+ // Get the relative path for display in the replay command
78
+ const shortPath = path_1.default.join(taskName, `${uuid}.json`);
79
+ console.log(`
80
+ ==================================================
81
+ Fixture download completed!
82
+ ==================================================
83
+ Fixture UUID: ${uuid}
84
+ Task Name: ${taskName}
85
+ Saved to: ${filePath}
86
+ ==================================================
87
+ Boundaries: ${Object.keys(fixture.boundaries).join(', ')}
88
+ ==================================================
89
+ Replay with:
90
+ forge task:replay ${taskName} --path ${shortPath}
91
+ ==================================================
92
+ `);
101
93
  return {
102
94
  status: 'Downloaded',
103
- path: filePath
95
+ path: filePath,
96
+ shortPath: shortPath
104
97
  };
105
98
  });
106
99
  exports.download.setDescription(description);
@@ -1,7 +1,8 @@
1
1
  import { type ForgeConf, type Profile } from '../types';
2
2
  interface Fixture {
3
3
  fixtureUUID: string;
4
- name: string;
4
+ taskName: string;
5
+ projectName: string;
5
6
  type: 'success' | 'error';
6
7
  input: Record<string, unknown>;
7
8
  output: Record<string, unknown>;
@@ -10,6 +11,7 @@ interface Fixture {
10
11
  }
11
12
  export declare const replay: import("@forgehive/task").TaskInstanceType<(argv: {
12
13
  path: string;
14
+ descriptorName: string;
13
15
  cache?: string | undefined;
14
16
  }, boundaries: import("@forgehive/task").WrappedBoundaries<{
15
17
  readFixture: (filePath: string) => Promise<Fixture>;
@@ -19,6 +19,7 @@ const load_2 = require("../conf/load");
19
19
  const loadCurrent_1 = require("../auth/loadCurrent");
20
20
  const description = 'Replay a task execution from a specified path';
21
21
  const schema = new schema_1.Schema({
22
+ descriptorName: schema_1.Schema.string(),
22
23
  path: schema_1.Schema.string(),
23
24
  cache: schema_1.Schema.string().optional()
24
25
  });
@@ -79,18 +80,23 @@ const boundaries = {
79
80
  }
80
81
  }
81
82
  };
82
- exports.replay = (0, task_1.createTask)(schema, boundaries, async function (argv, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
83
- console.log('Input path:', argv.path);
84
- // Read the file from the provided path
85
- const fixture = await readFixture(argv.path);
83
+ exports.replay = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName, path: fixturePath, cache }, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
84
+ console.log('Input descriptorName:', descriptorName);
85
+ console.log('Input path:', fixturePath);
86
+ console.log('Input cache:', cache);
86
87
  // Load forge configuration
87
88
  const forge = await loadConf({});
88
- const taskName = fixture.name;
89
- const taskDescriptor = forge.tasks[taskName];
89
+ const taskDescriptor = forge.tasks[descriptorName];
90
90
  const projectName = forge.project.name;
91
91
  if (taskDescriptor === undefined) {
92
- throw new Error(`Task ${taskName} is not defined in forge.json`);
92
+ throw new Error(`Task ${descriptorName} is not defined in forge.json`);
93
93
  }
94
+ // Resolve the fixture path (check if absolute, if not make it relative to logs folder)
95
+ const resolvedFixturePath = path_1.default.isAbsolute(fixturePath)
96
+ ? fixturePath
97
+ : path_1.default.join(process.cwd(), forge.paths.fixtures, fixturePath);
98
+ // Read the file from the provided path
99
+ const fixture = await readFixture(resolvedFixturePath);
94
100
  // Try to load profile, but continue if not found
95
101
  let profile = null;
96
102
  try {
@@ -109,7 +115,7 @@ exports.replay = (0, task_1.createTask)(schema, boundaries, async function (argv
109
115
  // Prepare paths
110
116
  const entryPoint = path_1.default.join(process.cwd(), taskDescriptor.path);
111
117
  const buildsPath = await ensureBuildsFolder();
112
- const outputFile = path_1.default.join(buildsPath, `${taskName}.js`);
118
+ const outputFile = path_1.default.join(buildsPath, `${descriptorName}.js`);
113
119
  // Bundle the task
114
120
  await bundleCreate({
115
121
  entryPoint,
@@ -126,20 +132,21 @@ exports.replay = (0, task_1.createTask)(schema, boundaries, async function (argv
126
132
  }
127
133
  // Configure boundaries based on cache parameter if provided
128
134
  const boundaryConfig = {};
129
- if (argv.cache) {
135
+ if (cache) {
130
136
  // Parse the comma-separated list and trim each item
131
- const cacheBoundaries = argv.cache.split(',').map(b => b.trim());
137
+ const cacheBoundaries = cache.split(',').map((b) => b.trim());
132
138
  // Log which boundaries will use cache mode
133
139
  if (cacheBoundaries.length > 0) {
134
140
  // Set each specified boundary to 'replay' mode
135
- cacheBoundaries.forEach(boundary => {
141
+ cacheBoundaries.forEach((boundary) => {
136
142
  boundaryConfig[boundary] = 'replay';
137
143
  });
138
144
  }
139
145
  }
140
146
  console.log('==================================================');
141
147
  console.log('UUID:', fixture.fixtureUUID);
142
- console.log('Name:', fixture.name);
148
+ console.log('Task name:', fixture.taskName);
149
+ console.log('Project name:', fixture.projectName);
143
150
  console.log('Context:', fixture.context);
144
151
  console.log('==================================================');
145
152
  console.log('Replay:', fixture.input);
@@ -158,7 +165,7 @@ exports.replay = (0, task_1.createTask)(schema, boundaries, async function (argv
158
165
  // Send the log to API if profile is available
159
166
  if (profile) {
160
167
  try {
161
- await sendLogToAPI(profile, projectName, taskName, record, fixture.fixtureUUID);
168
+ await sendLogToAPI(profile, projectName, descriptorName, record, fixture.fixtureUUID);
162
169
  }
163
170
  catch (e) {
164
171
  console.error('Failed to send log to API:', e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgehive/forge-cli",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "TypeScript CLI application",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -10,10 +10,10 @@
10
10
  "publishConfig": {
11
11
  "access": "public",
12
12
  "dependencies": {
13
- "@forgehive/record-tape": "^0.1.3",
14
- "@forgehive/runner": "^0.1.9",
13
+ "@forgehive/record-tape": "^0.1.4",
14
+ "@forgehive/runner": "^0.1.10",
15
15
  "@forgehive/schema": "^0.1.4",
16
- "@forgehive/task": "^0.1.9",
16
+ "@forgehive/task": "^0.1.11",
17
17
  "esbuild": "^0.25.0",
18
18
  "handlebars": "^4.7.8",
19
19
  "minimist": "^1.2.8"
@@ -25,10 +25,10 @@
25
25
  "esbuild": "^0.25.0",
26
26
  "handlebars": "^4.7.8",
27
27
  "minimist": "^1.2.8",
28
- "@forgehive/runner": "0.1.9",
28
+ "@forgehive/runner": "0.1.10",
29
+ "@forgehive/record-tape": "0.1.4",
29
30
  "@forgehive/schema": "0.1.4",
30
- "@forgehive/task": "0.1.9",
31
- "@forgehive/record-tape": "0.1.3"
31
+ "@forgehive/task": "0.1.11"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/jest": "^29.5.3",
package/src/index.ts CHANGED
@@ -5,9 +5,23 @@ import runner from './runner'
5
5
 
6
6
  const args = minimist(process.argv.slice(2))
7
7
 
8
- runner.handler(args).then(data => {
8
+ type RunnerResult = {
9
+ silent: boolean
10
+ outcome: 'Success' | 'Failure'
11
+ taskName: string
12
+ result: unknown
13
+ }
14
+
15
+ runner.handler(args).then((data) => {
16
+ const { silent, outcome, result } = data as RunnerResult
17
+ if (silent) {
18
+ return
19
+ }
20
+
21
+ console.log('===============================================')
22
+ console.log(`Outcome: ${outcome}`)
9
23
  console.log('===============================================')
10
- console.log('Outcome', data)
24
+ console.log('Result', result)
11
25
  console.log('===============================================')
12
26
  }).catch((e) => {
13
27
  console.error(e)
package/src/runner.ts CHANGED
@@ -72,10 +72,11 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
72
72
  const parsedArgs = runner.parseArguments(data)
73
73
  const { taskName, action, args } = parsedArgs
74
74
 
75
- console.log('========================================')
75
+ console.log('===============================================')
76
76
  console.log(`Running: ${taskName} ${action ? action : ''} ${JSON.stringify(args)}`)
77
- console.log('========================================')
77
+ console.log('===============================================')
78
78
 
79
+ let silent = false
79
80
  const task = runner.getTask(taskName)
80
81
  if (!task) {
81
82
  throw new Error(`Task "${taskName}" not found`)
@@ -128,6 +129,7 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
128
129
  descriptorName: action,
129
130
  uuid
130
131
  })
132
+ silent = true
131
133
  } else if (taskName === 'auth:add') {
132
134
  const { apiKey, apiSecret, url } = args as { name: string, apiKey: string, apiSecret: string, url: string }
133
135
 
@@ -146,6 +148,7 @@ runner.setHandler(async (data: ParsedArgs): Promise<unknown> => {
146
148
  }
147
149
 
148
150
  return {
151
+ silent,
149
152
  outcome: 'Success',
150
153
  taskName,
151
154
  result
@@ -14,6 +14,7 @@ import { Profile } from '../types'
14
14
  // Define the Fixture data structure
15
15
  interface FixtureData {
16
16
  name: string;
17
+ boundaries: Record<string, unknown>;
17
18
  [key: string]: unknown;
18
19
  }
19
20
 
@@ -58,14 +59,6 @@ const boundaries = {
58
59
  return {
59
60
  path: filePath
60
61
  }
61
- },
62
- checkFileExists: async (filePath: string): Promise<boolean> => {
63
- try {
64
- await fs.access(filePath)
65
- return true
66
- } catch {
67
- return false
68
- }
69
62
  }
70
63
  }
71
64
 
@@ -76,12 +69,12 @@ export const download = createTask(
76
69
  downloadFixture,
77
70
  getCwd,
78
71
  persistFixture,
79
- checkFileExists,
80
72
  loadCurrentProfile,
81
73
  loadConf
82
74
  }) {
83
75
  console.log('==================================================')
84
76
  console.log(`Attempting to download fixture with uuid: ${uuid}`)
77
+ console.log('==================================================')
85
78
 
86
79
  const profile = await loadCurrentProfile({})
87
80
  const cwd = await getCwd()
@@ -102,8 +95,8 @@ export const download = createTask(
102
95
  throw new Error('Failed to download fixture')
103
96
  }
104
97
 
105
- // Extract task descriptor from the response
106
- const taskName = response.fixture.name
98
+ const fixture = response.fixture as FixtureData
99
+ const taskName = fixture.taskName as string
107
100
 
108
101
  // Determine the output path using forge fixtures path and task descriptor
109
102
  const fixturesBasePath = forge.paths.fixtures || 'fixtures'
@@ -111,31 +104,31 @@ export const download = createTask(
111
104
  const fixturePath = path.join(fixtureDir, `${uuid}.json`)
112
105
  const filePath = path.resolve(cwd, fixturePath)
113
106
 
114
- console.log(`Fixture will be saved to: ${filePath}`)
107
+ // Persist fixture to file
108
+ await persistFixture(filePath, response.fixture)
115
109
 
116
- // Check if file already exists
117
- const fileExists = await checkFileExists(filePath)
118
- if (fileExists) {
119
- console.log(`Fixture will be updated at ${filePath}`)
120
- }
110
+ // Get the relative path for display in the replay command
111
+ const shortPath = path.join(taskName, `${uuid}.json`)
121
112
 
122
113
  console.log(`
123
- ==================================================
124
- Starting fixture download!
125
- Fixture UUID: ${uuid}
126
- Task Name: ${taskName}
127
- Saving to: ${filePath}
128
- ==================================================
129
- Replay with: forge task:replay --path ${filePath}
130
- ==================================================
114
+ ==================================================
115
+ Fixture download completed!
116
+ ==================================================
117
+ Fixture UUID: ${uuid}
118
+ Task Name: ${taskName}
119
+ Saved to: ${filePath}
120
+ ==================================================
121
+ Boundaries: ${Object.keys(fixture.boundaries).join(', ')}
122
+ ==================================================
123
+ Replay with:
124
+ forge task:replay ${taskName} --path ${shortPath}
125
+ ==================================================
131
126
  `)
132
127
 
133
- // Persist fixture to file
134
- await persistFixture(filePath, response.fixture)
135
-
136
128
  return {
137
129
  status: 'Downloaded',
138
- path: filePath
130
+ path: filePath,
131
+ shortPath: shortPath
139
132
  }
140
133
  }
141
134
  )
@@ -18,7 +18,8 @@ import { type ForgeConf, type Profile } from '../types'
18
18
  // Define the fixture structure type
19
19
  interface Fixture {
20
20
  fixtureUUID: string;
21
- name: string;
21
+ taskName: string;
22
+ projectName: string;
22
23
  type: 'success' | 'error';
23
24
  input: Record<string, unknown>;
24
25
  output: Record<string, unknown>;
@@ -29,6 +30,7 @@ interface Fixture {
29
30
  const description = 'Replay a task execution from a specified path'
30
31
 
31
32
  const schema = new Schema({
33
+ descriptorName: Schema.string(),
32
34
  path: Schema.string(),
33
35
  cache: Schema.string().optional()
34
36
  })
@@ -97,22 +99,28 @@ const boundaries = {
97
99
  export const replay = createTask(
98
100
  schema,
99
101
  boundaries,
100
- async function (argv, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
101
- console.log('Input path:', argv.path)
102
-
103
- // Read the file from the provided path
104
- const fixture = await readFixture(argv.path)
102
+ async function ({ descriptorName, path: fixturePath, cache }, { readFixture, loadConf, loadCurrentProfile, bundleCreate, bundleLoad, ensureBuildsFolder, verifyLogFolder, sendLogToAPI }) {
103
+ console.log('Input descriptorName:', descriptorName)
104
+ console.log('Input path:', fixturePath)
105
+ console.log('Input cache:', cache)
105
106
 
106
107
  // Load forge configuration
107
108
  const forge: ForgeConf = await loadConf({})
108
- const taskName = fixture.name
109
- const taskDescriptor = forge.tasks[taskName as keyof typeof forge.tasks]
109
+ const taskDescriptor = forge.tasks[descriptorName as keyof typeof forge.tasks]
110
110
  const projectName = forge.project.name
111
111
 
112
112
  if (taskDescriptor === undefined) {
113
- throw new Error(`Task ${taskName} is not defined in forge.json`)
113
+ throw new Error(`Task ${descriptorName} is not defined in forge.json`)
114
114
  }
115
115
 
116
+ // Resolve the fixture path (check if absolute, if not make it relative to logs folder)
117
+ const resolvedFixturePath = path.isAbsolute(fixturePath)
118
+ ? fixturePath
119
+ : path.join(process.cwd(), forge.paths.fixtures, fixturePath)
120
+
121
+ // Read the file from the provided path
122
+ const fixture = await readFixture(resolvedFixturePath)
123
+
116
124
  // Try to load profile, but continue if not found
117
125
  let profile = null
118
126
  try {
@@ -132,7 +140,7 @@ export const replay = createTask(
132
140
  // Prepare paths
133
141
  const entryPoint = path.join(process.cwd(), taskDescriptor.path)
134
142
  const buildsPath = await ensureBuildsFolder()
135
- const outputFile = path.join(buildsPath, `${taskName}.js`)
143
+ const outputFile = path.join(buildsPath, `${descriptorName}.js`)
136
144
 
137
145
  // Bundle the task
138
146
  await bundleCreate({
@@ -155,14 +163,14 @@ export const replay = createTask(
155
163
  // Configure boundaries based on cache parameter if provided
156
164
  const boundaryConfig: Record<string, string> = {}
157
165
 
158
- if (argv.cache) {
166
+ if (cache) {
159
167
  // Parse the comma-separated list and trim each item
160
- const cacheBoundaries = argv.cache.split(',').map(b => b.trim())
168
+ const cacheBoundaries = cache.split(',').map((b: string) => b.trim())
161
169
 
162
170
  // Log which boundaries will use cache mode
163
171
  if (cacheBoundaries.length > 0) {
164
172
  // Set each specified boundary to 'replay' mode
165
- cacheBoundaries.forEach(boundary => {
173
+ cacheBoundaries.forEach((boundary: string) => {
166
174
  boundaryConfig[boundary] = 'replay'
167
175
  })
168
176
  }
@@ -170,7 +178,8 @@ export const replay = createTask(
170
178
 
171
179
  console.log('==================================================')
172
180
  console.log('UUID:', fixture.fixtureUUID)
173
- console.log('Name:', fixture.name)
181
+ console.log('Task name:', fixture.taskName)
182
+ console.log('Project name:', fixture.projectName)
174
183
  console.log('Context:', fixture.context)
175
184
  console.log('==================================================')
176
185
  console.log('Replay:', fixture.input)
@@ -194,7 +203,7 @@ export const replay = createTask(
194
203
  // Send the log to API if profile is available
195
204
  if (profile) {
196
205
  try {
197
- await sendLogToAPI(profile, projectName, taskName, record, fixture.fixtureUUID)
206
+ await sendLogToAPI(profile, projectName, descriptorName, record, fixture.fixtureUUID)
198
207
  } catch (e) {
199
208
  console.error('Failed to send log to API:', e)
200
209
  }