@forgehive/forge-cli 0.2.4 → 0.2.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/dist/tasks/init.js +1 -1
- package/dist/tasks/task/publish.js +2 -0
- package/dist/tasks/task/run.d.ts +5 -1
- package/dist/tasks/task/run.js +54 -5
- package/dist/test/tasks/init.test.js +2 -2
- package/package.json +3 -3
- package/src/tasks/init.ts +1 -1
- package/src/tasks/task/publish.ts +2 -0
- package/src/tasks/task/run.ts +66 -6
- package/src/test/tasks/init.test.ts +2 -2
package/dist/tasks/init.js
CHANGED
|
@@ -101,6 +101,7 @@ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ d
|
|
|
101
101
|
const task = bundle[taskDescriptor.handler];
|
|
102
102
|
const description = task.getDescription() ?? '';
|
|
103
103
|
const schema = task.getSchema() || new schema_1.Schema({});
|
|
104
|
+
const boundaries = Object.keys(task.getBoundaries()) || [];
|
|
104
105
|
const schemaDescriptor = schema.describe();
|
|
105
106
|
// Read the task file content
|
|
106
107
|
const sourceCode = await readFileUtf8(entryPoint);
|
|
@@ -114,6 +115,7 @@ exports.publish = (0, task_1.createTask)(schema, boundaries, async function ({ d
|
|
|
114
115
|
projectName,
|
|
115
116
|
description,
|
|
116
117
|
schemaDescriptor: JSON.stringify(schemaDescriptor),
|
|
118
|
+
boundaries,
|
|
117
119
|
sourceCode,
|
|
118
120
|
bundleSize
|
|
119
121
|
};
|
package/dist/tasks/task/run.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { type ForgeConf } from '../types';
|
|
1
|
+
import { type ForgeConf, type Profile } from '../types';
|
|
2
2
|
export declare const run: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
3
3
|
descriptorName: string;
|
|
4
4
|
args: Record<string, string | number | boolean>;
|
|
5
5
|
}, boundaries: import("@forgehive/task").WrappedBoundaries<{
|
|
6
6
|
loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
|
|
7
|
+
loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
|
|
7
8
|
bundleCreate: (args: {
|
|
8
9
|
entryPoint: string;
|
|
9
10
|
outputFile: string;
|
|
@@ -15,8 +16,10 @@ export declare const run: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
|
15
16
|
}) => Promise<Promise<any>>;
|
|
16
17
|
verifyLogFolder: (logsPath: string) => Promise<boolean>;
|
|
17
18
|
ensureBuildsFolder: () => Promise<string>;
|
|
19
|
+
sendLogToAPI: (profile: Profile, projectName: string, taskName: string, logItem: unknown) => Promise<boolean>;
|
|
18
20
|
}>) => Promise<any>, {
|
|
19
21
|
loadConf: (args: {}) => Promise<Promise<ForgeConf>>;
|
|
22
|
+
loadCurrentProfile: (args: {}) => Promise<Promise<Profile>>;
|
|
20
23
|
bundleCreate: (args: {
|
|
21
24
|
entryPoint: string;
|
|
22
25
|
outputFile: string;
|
|
@@ -28,4 +31,5 @@ export declare const run: import("@forgehive/task").TaskInstanceType<(argv: {
|
|
|
28
31
|
}) => Promise<Promise<any>>;
|
|
29
32
|
verifyLogFolder: (logsPath: string) => Promise<boolean>;
|
|
30
33
|
ensureBuildsFolder: () => Promise<string>;
|
|
34
|
+
sendLogToAPI: (profile: Profile, projectName: string, taskName: string, logItem: unknown) => Promise<boolean>;
|
|
31
35
|
}>;
|
package/dist/tasks/task/run.js
CHANGED
|
@@ -10,12 +10,14 @@ exports.run = void 0;
|
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
12
12
|
const os_1 = __importDefault(require("os"));
|
|
13
|
+
const axios_1 = __importDefault(require("axios"));
|
|
13
14
|
const task_1 = require("@forgehive/task");
|
|
14
15
|
const schema_1 = require("@forgehive/schema");
|
|
15
16
|
const record_tape_1 = require("@forgehive/record-tape");
|
|
16
17
|
const create_1 = require("../bundle/create");
|
|
17
18
|
const load_1 = require("../bundle/load");
|
|
18
19
|
const load_2 = require("../conf/load");
|
|
20
|
+
const loadCurrent_1 = require("../auth/loadCurrent");
|
|
19
21
|
// For now, we'll use a simple schema without the record type
|
|
20
22
|
// TODO: Use Schema.record once it's properly built and available
|
|
21
23
|
const schema = new schema_1.Schema({
|
|
@@ -25,6 +27,7 @@ const schema = new schema_1.Schema({
|
|
|
25
27
|
});
|
|
26
28
|
const boundaries = {
|
|
27
29
|
loadConf: load_2.load.asBoundary(),
|
|
30
|
+
loadCurrentProfile: loadCurrent_1.loadCurrent.asBoundary(),
|
|
28
31
|
bundleCreate: create_1.create.asBoundary(),
|
|
29
32
|
bundleLoad: load_1.load.asBoundary(),
|
|
30
33
|
verifyLogFolder: async (logsPath) => {
|
|
@@ -46,15 +49,49 @@ const boundaries = {
|
|
|
46
49
|
await promises_1.default.mkdir(buildsPath, { recursive: true });
|
|
47
50
|
}
|
|
48
51
|
return buildsPath;
|
|
52
|
+
},
|
|
53
|
+
sendLogToAPI: async (profile, projectName, taskName, logItem) => {
|
|
54
|
+
try {
|
|
55
|
+
const logsUrl = `${profile.url}/api/tasks/log-ingest`;
|
|
56
|
+
const authToken = `${profile.apiKey}:${profile.apiSecret}`;
|
|
57
|
+
await axios_1.default.post(logsUrl, {
|
|
58
|
+
projectName,
|
|
59
|
+
taskName,
|
|
60
|
+
logItem: JSON.stringify(logItem)
|
|
61
|
+
}, {
|
|
62
|
+
headers: {
|
|
63
|
+
Authorization: `Bearer ${authToken}`,
|
|
64
|
+
'Content-Type': 'application/json'
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
console.log('===============================================');
|
|
68
|
+
console.log('Log sent to API... ', profile.name, profile.url);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
const error = e;
|
|
73
|
+
console.error('Failed to send log to API:', error.message);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
49
76
|
}
|
|
50
77
|
};
|
|
51
|
-
exports.run = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName, args }, { loadConf, bundleCreate, bundleLoad, verifyLogFolder, ensureBuildsFolder }) {
|
|
78
|
+
exports.run = (0, task_1.createTask)(schema, boundaries, async function ({ descriptorName, args }, { loadConf, bundleCreate, bundleLoad, verifyLogFolder, ensureBuildsFolder, loadCurrentProfile, sendLogToAPI }) {
|
|
52
79
|
// Load forge configuration
|
|
53
80
|
const forge = await loadConf({});
|
|
54
81
|
const taskDescriptor = forge.tasks[descriptorName];
|
|
82
|
+
const projectName = forge.project.name;
|
|
55
83
|
if (taskDescriptor === undefined) {
|
|
56
84
|
throw new Error('Task is not defined on forge.json');
|
|
57
85
|
}
|
|
86
|
+
// Try to load profile, but continue if not found
|
|
87
|
+
let profile = null;
|
|
88
|
+
try {
|
|
89
|
+
profile = await loadCurrentProfile({});
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
// Profile not found or not configured, continue without it
|
|
93
|
+
console.log('No profile found, logs will not be sent to remote API');
|
|
94
|
+
}
|
|
58
95
|
// Verify if log folder exists
|
|
59
96
|
const logFolderPath = path_1.default.join(process.cwd(), forge.paths.logs);
|
|
60
97
|
const logFolderExists = await verifyLogFolder(logFolderPath);
|
|
@@ -105,14 +142,26 @@ exports.run = (0, task_1.createTask)(schema, boundaries, async function ({ descr
|
|
|
105
142
|
}
|
|
106
143
|
tape.recordFrom(descriptorName, task);
|
|
107
144
|
// Run the task with provided arguments
|
|
108
|
-
let result;
|
|
145
|
+
let result, error;
|
|
109
146
|
try {
|
|
110
147
|
result = await task.run(args);
|
|
111
148
|
}
|
|
112
|
-
catch (
|
|
113
|
-
|
|
114
|
-
throw error;
|
|
149
|
+
catch (e) {
|
|
150
|
+
error = e;
|
|
115
151
|
}
|
|
116
152
|
await tape.save();
|
|
153
|
+
const logItems = tape.getLog();
|
|
154
|
+
const lastLogItem = logItems[logItems.length - 1];
|
|
155
|
+
if (profile) {
|
|
156
|
+
try {
|
|
157
|
+
await sendLogToAPI(profile, projectName, descriptorName, lastLogItem);
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
console.error('Failed to send log to API:', e);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (error) {
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
117
166
|
return result;
|
|
118
167
|
});
|
|
@@ -43,7 +43,7 @@ describe('Init task', () => {
|
|
|
43
43
|
const fileContent = await fs.promises.readFile(path_1.default.join(rootDir, 'forge.json'), 'utf-8');
|
|
44
44
|
const config = JSON.parse(fileContent);
|
|
45
45
|
// Verify the file content
|
|
46
|
-
expect(config).toHaveProperty('project.name', '
|
|
46
|
+
expect(config).toHaveProperty('project.name', 'BaseProject');
|
|
47
47
|
expect(config).toHaveProperty('paths.logs', 'logs/');
|
|
48
48
|
expect(config).toHaveProperty('paths.tasks', 'src/tasks/');
|
|
49
49
|
expect(config).toHaveProperty('infra.region', 'us-west-2');
|
|
@@ -66,7 +66,7 @@ describe('Init task', () => {
|
|
|
66
66
|
// Verify saveFile was not called
|
|
67
67
|
expect(saveFileFn).not.toHaveBeenCalled();
|
|
68
68
|
// Verify the returned config has the correct structure
|
|
69
|
-
expect(result).toHaveProperty('project.name', '
|
|
69
|
+
expect(result).toHaveProperty('project.name', 'BaseProject');
|
|
70
70
|
expect(result).toHaveProperty('paths.logs', 'logs/');
|
|
71
71
|
expect(result).toHaveProperty('paths.tasks', 'src/tasks/');
|
|
72
72
|
expect(result).toHaveProperty('infra.region', 'us-west-2');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgehive/forge-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "TypeScript CLI application",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"handlebars": "^4.7.8",
|
|
27
27
|
"minimist": "^1.2.8",
|
|
28
28
|
"@forgehive/task": "0.1.5",
|
|
29
|
+
"@forgehive/schema": "0.1.4",
|
|
29
30
|
"@forgehive/record-tape": "0.0.2",
|
|
30
|
-
"@forgehive/runner": "0.1.5"
|
|
31
|
-
"@forgehive/schema": "0.1.4"
|
|
31
|
+
"@forgehive/runner": "0.1.5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/jest": "^29.5.3",
|
package/src/tasks/init.ts
CHANGED
|
@@ -126,6 +126,7 @@ export const publish = createTask(
|
|
|
126
126
|
const task = bundle[taskDescriptor.handler]
|
|
127
127
|
const description = task.getDescription() ?? ''
|
|
128
128
|
const schema = task.getSchema() || new Schema({})
|
|
129
|
+
const boundaries = Object.keys(task.getBoundaries()) || []
|
|
129
130
|
const schemaDescriptor = schema.describe()
|
|
130
131
|
|
|
131
132
|
// Read the task file content
|
|
@@ -142,6 +143,7 @@ export const publish = createTask(
|
|
|
142
143
|
projectName,
|
|
143
144
|
description,
|
|
144
145
|
schemaDescriptor: JSON.stringify(schemaDescriptor),
|
|
146
|
+
boundaries,
|
|
145
147
|
sourceCode,
|
|
146
148
|
bundleSize
|
|
147
149
|
}
|
package/src/tasks/task/run.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import path from 'path'
|
|
6
6
|
import fs from 'fs/promises'
|
|
7
7
|
import os from 'os'
|
|
8
|
+
import axios from 'axios'
|
|
8
9
|
|
|
9
10
|
import { createTask } from '@forgehive/task'
|
|
10
11
|
import { Schema } from '@forgehive/schema'
|
|
@@ -13,7 +14,8 @@ import { RecordTape } from '@forgehive/record-tape'
|
|
|
13
14
|
import { create as bundleCreate } from '../bundle/create'
|
|
14
15
|
import { load as bundleLoad } from '../bundle/load'
|
|
15
16
|
import { load as loadConf } from '../conf/load'
|
|
16
|
-
import {
|
|
17
|
+
import { loadCurrent as loadCurrentProfile } from '../auth/loadCurrent'
|
|
18
|
+
import { type ForgeConf, type Profile } from '../types'
|
|
17
19
|
|
|
18
20
|
// For now, we'll use a simple schema without the record type
|
|
19
21
|
// TODO: Use Schema.record once it's properly built and available
|
|
@@ -25,6 +27,7 @@ const schema = new Schema({
|
|
|
25
27
|
|
|
26
28
|
const boundaries = {
|
|
27
29
|
loadConf: loadConf.asBoundary(),
|
|
30
|
+
loadCurrentProfile: loadCurrentProfile.asBoundary(),
|
|
28
31
|
bundleCreate: bundleCreate.asBoundary(),
|
|
29
32
|
bundleLoad: bundleLoad.asBoundary(),
|
|
30
33
|
verifyLogFolder: async (logsPath: string): Promise<boolean> => {
|
|
@@ -46,21 +49,65 @@ const boundaries = {
|
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
return buildsPath
|
|
52
|
+
},
|
|
53
|
+
sendLogToAPI: async (profile: Profile, projectName: string, taskName: string, logItem: unknown): Promise<boolean> => {
|
|
54
|
+
try {
|
|
55
|
+
const logsUrl = `${profile.url}/api/tasks/log-ingest`
|
|
56
|
+
const authToken = `${profile.apiKey}:${profile.apiSecret}`
|
|
57
|
+
|
|
58
|
+
await axios.post(logsUrl, {
|
|
59
|
+
projectName,
|
|
60
|
+
taskName,
|
|
61
|
+
logItem: JSON.stringify(logItem)
|
|
62
|
+
}, {
|
|
63
|
+
headers: {
|
|
64
|
+
Authorization: `Bearer ${authToken}`,
|
|
65
|
+
'Content-Type': 'application/json'
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
console.log('===============================================')
|
|
70
|
+
console.log('Log sent to API... ', profile.name, profile.url)
|
|
71
|
+
|
|
72
|
+
return true
|
|
73
|
+
} catch (e) {
|
|
74
|
+
const error = e as Error
|
|
75
|
+
console.error('Failed to send log to API:', error.message)
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
49
78
|
}
|
|
50
79
|
}
|
|
51
80
|
|
|
52
81
|
export const run = createTask(
|
|
53
82
|
schema,
|
|
54
83
|
boundaries,
|
|
55
|
-
async function ({ descriptorName, args }, {
|
|
84
|
+
async function ({ descriptorName, args }, {
|
|
85
|
+
loadConf,
|
|
86
|
+
bundleCreate,
|
|
87
|
+
bundleLoad,
|
|
88
|
+
verifyLogFolder,
|
|
89
|
+
ensureBuildsFolder,
|
|
90
|
+
loadCurrentProfile,
|
|
91
|
+
sendLogToAPI
|
|
92
|
+
}) {
|
|
56
93
|
// Load forge configuration
|
|
57
94
|
const forge: ForgeConf = await loadConf({})
|
|
58
95
|
const taskDescriptor = forge.tasks[descriptorName as keyof typeof forge.tasks]
|
|
96
|
+
const projectName = forge.project.name
|
|
59
97
|
|
|
60
98
|
if (taskDescriptor === undefined) {
|
|
61
99
|
throw new Error('Task is not defined on forge.json')
|
|
62
100
|
}
|
|
63
101
|
|
|
102
|
+
// Try to load profile, but continue if not found
|
|
103
|
+
let profile = null
|
|
104
|
+
try {
|
|
105
|
+
profile = await loadCurrentProfile({})
|
|
106
|
+
} catch (error) {
|
|
107
|
+
// Profile not found or not configured, continue without it
|
|
108
|
+
console.log('No profile found, logs will not be sent to remote API')
|
|
109
|
+
}
|
|
110
|
+
|
|
64
111
|
// Verify if log folder exists
|
|
65
112
|
const logFolderPath = path.join(process.cwd(), forge.paths.logs)
|
|
66
113
|
const logFolderExists = await verifyLogFolder(logFolderPath)
|
|
@@ -122,15 +169,28 @@ export const run = createTask(
|
|
|
122
169
|
tape.recordFrom(descriptorName, task)
|
|
123
170
|
|
|
124
171
|
// Run the task with provided arguments
|
|
125
|
-
let result
|
|
172
|
+
let result, error
|
|
126
173
|
try {
|
|
127
174
|
result = await task.run(args)
|
|
128
|
-
} catch (
|
|
129
|
-
|
|
130
|
-
throw error
|
|
175
|
+
} catch (e) {
|
|
176
|
+
error = e as Error
|
|
131
177
|
}
|
|
132
178
|
|
|
133
179
|
await tape.save()
|
|
180
|
+
const logItems = tape.getLog()
|
|
181
|
+
const lastLogItem = logItems[logItems.length - 1]
|
|
182
|
+
|
|
183
|
+
if (profile) {
|
|
184
|
+
try {
|
|
185
|
+
await sendLogToAPI(profile, projectName, descriptorName, lastLogItem)
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error('Failed to send log to API:', e)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (error) {
|
|
192
|
+
throw error
|
|
193
|
+
}
|
|
134
194
|
|
|
135
195
|
return result
|
|
136
196
|
}
|
|
@@ -48,7 +48,7 @@ describe('Init task', () => {
|
|
|
48
48
|
const config = JSON.parse(fileContent)
|
|
49
49
|
|
|
50
50
|
// Verify the file content
|
|
51
|
-
expect(config).toHaveProperty('project.name', '
|
|
51
|
+
expect(config).toHaveProperty('project.name', 'BaseProject')
|
|
52
52
|
expect(config).toHaveProperty('paths.logs', 'logs/')
|
|
53
53
|
expect(config).toHaveProperty('paths.tasks', 'src/tasks/')
|
|
54
54
|
expect(config).toHaveProperty('infra.region', 'us-west-2')
|
|
@@ -77,7 +77,7 @@ describe('Init task', () => {
|
|
|
77
77
|
expect(saveFileFn).not.toHaveBeenCalled()
|
|
78
78
|
|
|
79
79
|
// Verify the returned config has the correct structure
|
|
80
|
-
expect(result).toHaveProperty('project.name', '
|
|
80
|
+
expect(result).toHaveProperty('project.name', 'BaseProject')
|
|
81
81
|
expect(result).toHaveProperty('paths.logs', 'logs/')
|
|
82
82
|
expect(result).toHaveProperty('paths.tasks', 'src/tasks/')
|
|
83
83
|
expect(result).toHaveProperty('infra.region', 'us-west-2')
|