@orange-soft/strapi-deployment-trigger 1.0.0 → 1.1.0
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/README.md +2 -10
- package/admin/src/pages/HomePage.jsx +109 -61
- package/admin/src/pages/SettingsPage.jsx +270 -97
- package/dist/_chunks/App-CuSCtdH7.js +666 -0
- package/dist/_chunks/App-vakyp6FE.mjs +666 -0
- package/dist/_chunks/{index-C18aSW5z.mjs → index-CZWWYGR3.mjs} +1 -1
- package/dist/_chunks/{index-CqpMwL_C.js → index-DGatQB-9.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +160 -38
- package/dist/server/index.mjs +160 -38
- package/package.json +1 -1
- package/server/src/controllers/controller.js +58 -3
- package/server/src/routes/admin/index.js +25 -0
- package/server/src/services/service.js +113 -43
- package/dist/_chunks/App-3JntxPYv.js +0 -520
- package/dist/_chunks/App-C0Byi5W1.mjs +0 -520
|
@@ -37,7 +37,7 @@ const index = {
|
|
|
37
37
|
defaultMessage: PLUGIN_ID
|
|
38
38
|
},
|
|
39
39
|
Component: async () => {
|
|
40
|
-
const { App } = await Promise.resolve().then(() => require("./App-
|
|
40
|
+
const { App } = await Promise.resolve().then(() => require("./App-CuSCtdH7.js"));
|
|
41
41
|
return App;
|
|
42
42
|
}
|
|
43
43
|
});
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -38,10 +38,36 @@ const controller = ({ strapi }) => ({
|
|
|
38
38
|
hasToken,
|
|
39
39
|
settings,
|
|
40
40
|
parsed: { owner, repo }
|
|
41
|
-
// Include parsed values for display
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
43
|
},
|
|
44
|
+
// Target CRUD operations
|
|
45
|
+
async addTarget(ctx) {
|
|
46
|
+
const { data } = ctx.request.body;
|
|
47
|
+
const service2 = getService(strapi);
|
|
48
|
+
const target = await service2.addTarget(data);
|
|
49
|
+
ctx.body = { data: target };
|
|
50
|
+
},
|
|
51
|
+
async updateTarget(ctx) {
|
|
52
|
+
const { id } = ctx.params;
|
|
53
|
+
const { data } = ctx.request.body;
|
|
54
|
+
const service2 = getService(strapi);
|
|
55
|
+
const target = await service2.updateTarget(id, data);
|
|
56
|
+
if (!target) {
|
|
57
|
+
return ctx.notFound("Target not found");
|
|
58
|
+
}
|
|
59
|
+
ctx.body = { data: target };
|
|
60
|
+
},
|
|
61
|
+
async deleteTarget(ctx) {
|
|
62
|
+
const { id } = ctx.params;
|
|
63
|
+
const service2 = getService(strapi);
|
|
64
|
+
const deleted = await service2.deleteTarget(id);
|
|
65
|
+
if (!deleted) {
|
|
66
|
+
return ctx.notFound("Target not found");
|
|
67
|
+
}
|
|
68
|
+
ctx.body = { data: { success: true } };
|
|
69
|
+
},
|
|
70
|
+
// Trigger deployment for a specific target
|
|
45
71
|
async trigger(ctx) {
|
|
46
72
|
const service2 = getService(strapi);
|
|
47
73
|
const githubToken = await service2.getToken();
|
|
@@ -53,7 +79,22 @@ const controller = ({ strapi }) => ({
|
|
|
53
79
|
if (!owner || !repo) {
|
|
54
80
|
return ctx.badRequest("GitHub repository URL is not configured or invalid. Please configure it in Settings.");
|
|
55
81
|
}
|
|
56
|
-
const { workflow
|
|
82
|
+
const { targetId, workflow: overrideWorkflow, branch: overrideBranch } = ctx.request.body || {};
|
|
83
|
+
let workflow, branch, targetName;
|
|
84
|
+
if (targetId) {
|
|
85
|
+
const target = await service2.getTarget(targetId);
|
|
86
|
+
if (!target) {
|
|
87
|
+
return ctx.badRequest("Target not found");
|
|
88
|
+
}
|
|
89
|
+
workflow = overrideWorkflow || target.workflow;
|
|
90
|
+
branch = overrideBranch || target.branch;
|
|
91
|
+
targetName = target.name;
|
|
92
|
+
} else {
|
|
93
|
+
const firstTarget = settings.targets?.[0];
|
|
94
|
+
workflow = overrideWorkflow || firstTarget?.workflow || "deploy.yml";
|
|
95
|
+
branch = overrideBranch || firstTarget?.branch || "master";
|
|
96
|
+
targetName = firstTarget?.name || "Default";
|
|
97
|
+
}
|
|
57
98
|
const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
|
|
58
99
|
try {
|
|
59
100
|
const response = await fetch(url, {
|
|
@@ -70,13 +111,14 @@ const controller = ({ strapi }) => ({
|
|
|
70
111
|
strapi.log.error(`GitHub API error: ${response.status} - ${errorText}`);
|
|
71
112
|
return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
|
|
72
113
|
}
|
|
73
|
-
strapi.log.info(`Deployment triggered for ${owner}/${repo} on branch ${branch}`);
|
|
114
|
+
strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
|
|
74
115
|
const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
|
|
75
116
|
ctx.body = {
|
|
76
117
|
data: {
|
|
77
118
|
success: true,
|
|
78
119
|
message: `Deployment triggered successfully for ${owner}/${repo}`,
|
|
79
120
|
repository: `${owner}/${repo}`,
|
|
121
|
+
targetName,
|
|
80
122
|
workflow,
|
|
81
123
|
branch,
|
|
82
124
|
actionsUrl
|
|
@@ -141,6 +183,31 @@ const adminAPIRoutes = () => ({
|
|
|
141
183
|
config: {
|
|
142
184
|
policies: []
|
|
143
185
|
}
|
|
186
|
+
},
|
|
187
|
+
// Target CRUD routes
|
|
188
|
+
{
|
|
189
|
+
method: "POST",
|
|
190
|
+
path: "/targets",
|
|
191
|
+
handler: "controller.addTarget",
|
|
192
|
+
config: {
|
|
193
|
+
policies: []
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
method: "PUT",
|
|
198
|
+
path: "/targets/:id",
|
|
199
|
+
handler: "controller.updateTarget",
|
|
200
|
+
config: {
|
|
201
|
+
policies: []
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
method: "DELETE",
|
|
206
|
+
path: "/targets/:id",
|
|
207
|
+
handler: "controller.deleteTarget",
|
|
208
|
+
config: {
|
|
209
|
+
policies: []
|
|
210
|
+
}
|
|
144
211
|
}
|
|
145
212
|
]
|
|
146
213
|
});
|
|
@@ -152,9 +219,10 @@ const PLUGIN_ID = "deployment-trigger";
|
|
|
152
219
|
const STORE_KEY = "settings";
|
|
153
220
|
const DEFAULT_SETTINGS = {
|
|
154
221
|
repoUrl: "",
|
|
155
|
-
|
|
156
|
-
|
|
222
|
+
githubToken: "",
|
|
223
|
+
targets: []
|
|
157
224
|
};
|
|
225
|
+
const generateId = () => Math.random().toString(36).substring(2, 9);
|
|
158
226
|
const service = ({ strapi }) => ({
|
|
159
227
|
getWelcomeMessage() {
|
|
160
228
|
return "Welcome to Strapi Deployment Trigger";
|
|
@@ -177,35 +245,43 @@ const service = ({ strapi }) => ({
|
|
|
177
245
|
}
|
|
178
246
|
return { owner: null, repo: null };
|
|
179
247
|
},
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
248
|
+
// Migrate old single-config format to new multi-target format
|
|
249
|
+
migrateSettings(settings) {
|
|
250
|
+
if (!settings) return null;
|
|
251
|
+
if (Array.isArray(settings.targets)) {
|
|
252
|
+
return settings;
|
|
253
|
+
}
|
|
254
|
+
if (settings.workflow || settings.branch) {
|
|
186
255
|
return {
|
|
187
|
-
|
|
188
|
-
githubToken:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
256
|
+
repoUrl: settings.repoUrl || "",
|
|
257
|
+
githubToken: settings.githubToken || "",
|
|
258
|
+
targets: [{
|
|
259
|
+
id: generateId(),
|
|
260
|
+
name: "Default",
|
|
261
|
+
workflow: settings.workflow || "deploy.yml",
|
|
262
|
+
branch: settings.branch || "master"
|
|
263
|
+
}]
|
|
192
264
|
};
|
|
193
265
|
}
|
|
194
|
-
|
|
195
|
-
|
|
266
|
+
return settings;
|
|
267
|
+
},
|
|
268
|
+
async getSettings() {
|
|
269
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
270
|
+
let dbSettings = await store.get({ key: STORE_KEY });
|
|
271
|
+
dbSettings = this.migrateSettings(dbSettings);
|
|
272
|
+
if (!dbSettings) {
|
|
196
273
|
return {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
hasToken: !!envToken,
|
|
201
|
-
maskedToken: this.maskToken(envToken)
|
|
274
|
+
...DEFAULT_SETTINGS,
|
|
275
|
+
hasToken: false,
|
|
276
|
+
maskedToken: null
|
|
202
277
|
};
|
|
203
278
|
}
|
|
204
|
-
const token = dbSettings
|
|
279
|
+
const token = dbSettings.githubToken;
|
|
205
280
|
return {
|
|
206
|
-
|
|
207
|
-
|
|
281
|
+
repoUrl: dbSettings.repoUrl || "",
|
|
282
|
+
targets: dbSettings.targets || [],
|
|
208
283
|
githubToken: void 0,
|
|
284
|
+
// Never expose full token
|
|
209
285
|
hasToken: !!token,
|
|
210
286
|
maskedToken: this.maskToken(token)
|
|
211
287
|
};
|
|
@@ -213,33 +289,79 @@ const service = ({ strapi }) => ({
|
|
|
213
289
|
async saveSettings(settings) {
|
|
214
290
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
215
291
|
const existingSettings = await store.get({ key: STORE_KEY }) || {};
|
|
292
|
+
const migrated = this.migrateSettings(existingSettings);
|
|
216
293
|
const settingsToSave = {
|
|
217
|
-
repoUrl: settings.repoUrl,
|
|
218
|
-
|
|
219
|
-
branch: settings.branch || DEFAULT_SETTINGS.branch,
|
|
294
|
+
repoUrl: settings.repoUrl !== void 0 ? settings.repoUrl : migrated?.repoUrl || "",
|
|
295
|
+
targets: settings.targets !== void 0 ? settings.targets : migrated?.targets || [],
|
|
220
296
|
// Only update token if a new one is provided
|
|
221
|
-
githubToken: settings.githubToken ||
|
|
297
|
+
githubToken: settings.githubToken || migrated?.githubToken || ""
|
|
222
298
|
};
|
|
223
299
|
await store.set({ key: STORE_KEY, value: settingsToSave });
|
|
224
300
|
return {
|
|
225
|
-
|
|
301
|
+
repoUrl: settingsToSave.repoUrl,
|
|
302
|
+
targets: settingsToSave.targets,
|
|
226
303
|
githubToken: void 0,
|
|
227
|
-
hasToken: !!settingsToSave.githubToken
|
|
304
|
+
hasToken: !!settingsToSave.githubToken,
|
|
305
|
+
maskedToken: this.maskToken(settingsToSave.githubToken)
|
|
228
306
|
};
|
|
229
307
|
},
|
|
308
|
+
async addTarget(target) {
|
|
309
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
310
|
+
let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
|
|
311
|
+
settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
|
|
312
|
+
const newTarget = {
|
|
313
|
+
id: generateId(),
|
|
314
|
+
name: target.name || "New Target",
|
|
315
|
+
workflow: target.workflow || "deploy.yml",
|
|
316
|
+
branch: target.branch || "master"
|
|
317
|
+
};
|
|
318
|
+
settings.targets = [...settings.targets || [], newTarget];
|
|
319
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
320
|
+
return newTarget;
|
|
321
|
+
},
|
|
322
|
+
async updateTarget(targetId, updates) {
|
|
323
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
324
|
+
let settings = await store.get({ key: STORE_KEY });
|
|
325
|
+
settings = this.migrateSettings(settings);
|
|
326
|
+
if (!settings?.targets) return null;
|
|
327
|
+
const targetIndex = settings.targets.findIndex((t) => t.id === targetId);
|
|
328
|
+
if (targetIndex === -1) return null;
|
|
329
|
+
settings.targets[targetIndex] = {
|
|
330
|
+
...settings.targets[targetIndex],
|
|
331
|
+
...updates,
|
|
332
|
+
id: targetId
|
|
333
|
+
// Preserve ID
|
|
334
|
+
};
|
|
335
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
336
|
+
return settings.targets[targetIndex];
|
|
337
|
+
},
|
|
338
|
+
async deleteTarget(targetId) {
|
|
339
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
340
|
+
let settings = await store.get({ key: STORE_KEY });
|
|
341
|
+
settings = this.migrateSettings(settings);
|
|
342
|
+
if (!settings?.targets) return false;
|
|
343
|
+
const initialLength = settings.targets.length;
|
|
344
|
+
settings.targets = settings.targets.filter((t) => t.id !== targetId);
|
|
345
|
+
if (settings.targets.length === initialLength) return false;
|
|
346
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
347
|
+
return true;
|
|
348
|
+
},
|
|
349
|
+
async getTarget(targetId) {
|
|
350
|
+
const settings = await this.getSettings();
|
|
351
|
+
return settings.targets?.find((t) => t.id === targetId) || null;
|
|
352
|
+
},
|
|
230
353
|
async getToken() {
|
|
231
354
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
return process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
355
|
+
let dbSettings = await store.get({ key: STORE_KEY });
|
|
356
|
+
dbSettings = this.migrateSettings(dbSettings);
|
|
357
|
+
return dbSettings?.githubToken || null;
|
|
237
358
|
},
|
|
238
359
|
async isConfigured() {
|
|
239
360
|
const settings = await this.getSettings();
|
|
240
361
|
const hasToken = await this.getToken();
|
|
241
362
|
const { owner, repo } = this.parseRepoUrl(settings.repoUrl);
|
|
242
|
-
|
|
363
|
+
const hasTargets = settings.targets && settings.targets.length > 0;
|
|
364
|
+
return !!(owner && repo && hasToken && hasTargets);
|
|
243
365
|
},
|
|
244
366
|
async hasToken() {
|
|
245
367
|
const token = await this.getToken();
|
package/dist/server/index.mjs
CHANGED
|
@@ -37,10 +37,36 @@ const controller = ({ strapi }) => ({
|
|
|
37
37
|
hasToken,
|
|
38
38
|
settings,
|
|
39
39
|
parsed: { owner, repo }
|
|
40
|
-
// Include parsed values for display
|
|
41
40
|
}
|
|
42
41
|
};
|
|
43
42
|
},
|
|
43
|
+
// Target CRUD operations
|
|
44
|
+
async addTarget(ctx) {
|
|
45
|
+
const { data } = ctx.request.body;
|
|
46
|
+
const service2 = getService(strapi);
|
|
47
|
+
const target = await service2.addTarget(data);
|
|
48
|
+
ctx.body = { data: target };
|
|
49
|
+
},
|
|
50
|
+
async updateTarget(ctx) {
|
|
51
|
+
const { id } = ctx.params;
|
|
52
|
+
const { data } = ctx.request.body;
|
|
53
|
+
const service2 = getService(strapi);
|
|
54
|
+
const target = await service2.updateTarget(id, data);
|
|
55
|
+
if (!target) {
|
|
56
|
+
return ctx.notFound("Target not found");
|
|
57
|
+
}
|
|
58
|
+
ctx.body = { data: target };
|
|
59
|
+
},
|
|
60
|
+
async deleteTarget(ctx) {
|
|
61
|
+
const { id } = ctx.params;
|
|
62
|
+
const service2 = getService(strapi);
|
|
63
|
+
const deleted = await service2.deleteTarget(id);
|
|
64
|
+
if (!deleted) {
|
|
65
|
+
return ctx.notFound("Target not found");
|
|
66
|
+
}
|
|
67
|
+
ctx.body = { data: { success: true } };
|
|
68
|
+
},
|
|
69
|
+
// Trigger deployment for a specific target
|
|
44
70
|
async trigger(ctx) {
|
|
45
71
|
const service2 = getService(strapi);
|
|
46
72
|
const githubToken = await service2.getToken();
|
|
@@ -52,7 +78,22 @@ const controller = ({ strapi }) => ({
|
|
|
52
78
|
if (!owner || !repo) {
|
|
53
79
|
return ctx.badRequest("GitHub repository URL is not configured or invalid. Please configure it in Settings.");
|
|
54
80
|
}
|
|
55
|
-
const { workflow
|
|
81
|
+
const { targetId, workflow: overrideWorkflow, branch: overrideBranch } = ctx.request.body || {};
|
|
82
|
+
let workflow, branch, targetName;
|
|
83
|
+
if (targetId) {
|
|
84
|
+
const target = await service2.getTarget(targetId);
|
|
85
|
+
if (!target) {
|
|
86
|
+
return ctx.badRequest("Target not found");
|
|
87
|
+
}
|
|
88
|
+
workflow = overrideWorkflow || target.workflow;
|
|
89
|
+
branch = overrideBranch || target.branch;
|
|
90
|
+
targetName = target.name;
|
|
91
|
+
} else {
|
|
92
|
+
const firstTarget = settings.targets?.[0];
|
|
93
|
+
workflow = overrideWorkflow || firstTarget?.workflow || "deploy.yml";
|
|
94
|
+
branch = overrideBranch || firstTarget?.branch || "master";
|
|
95
|
+
targetName = firstTarget?.name || "Default";
|
|
96
|
+
}
|
|
56
97
|
const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
|
|
57
98
|
try {
|
|
58
99
|
const response = await fetch(url, {
|
|
@@ -69,13 +110,14 @@ const controller = ({ strapi }) => ({
|
|
|
69
110
|
strapi.log.error(`GitHub API error: ${response.status} - ${errorText}`);
|
|
70
111
|
return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
|
|
71
112
|
}
|
|
72
|
-
strapi.log.info(`Deployment triggered for ${owner}/${repo} on branch ${branch}`);
|
|
113
|
+
strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
|
|
73
114
|
const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
|
|
74
115
|
ctx.body = {
|
|
75
116
|
data: {
|
|
76
117
|
success: true,
|
|
77
118
|
message: `Deployment triggered successfully for ${owner}/${repo}`,
|
|
78
119
|
repository: `${owner}/${repo}`,
|
|
120
|
+
targetName,
|
|
79
121
|
workflow,
|
|
80
122
|
branch,
|
|
81
123
|
actionsUrl
|
|
@@ -140,6 +182,31 @@ const adminAPIRoutes = () => ({
|
|
|
140
182
|
config: {
|
|
141
183
|
policies: []
|
|
142
184
|
}
|
|
185
|
+
},
|
|
186
|
+
// Target CRUD routes
|
|
187
|
+
{
|
|
188
|
+
method: "POST",
|
|
189
|
+
path: "/targets",
|
|
190
|
+
handler: "controller.addTarget",
|
|
191
|
+
config: {
|
|
192
|
+
policies: []
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
method: "PUT",
|
|
197
|
+
path: "/targets/:id",
|
|
198
|
+
handler: "controller.updateTarget",
|
|
199
|
+
config: {
|
|
200
|
+
policies: []
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
method: "DELETE",
|
|
205
|
+
path: "/targets/:id",
|
|
206
|
+
handler: "controller.deleteTarget",
|
|
207
|
+
config: {
|
|
208
|
+
policies: []
|
|
209
|
+
}
|
|
143
210
|
}
|
|
144
211
|
]
|
|
145
212
|
});
|
|
@@ -151,9 +218,10 @@ const PLUGIN_ID = "deployment-trigger";
|
|
|
151
218
|
const STORE_KEY = "settings";
|
|
152
219
|
const DEFAULT_SETTINGS = {
|
|
153
220
|
repoUrl: "",
|
|
154
|
-
|
|
155
|
-
|
|
221
|
+
githubToken: "",
|
|
222
|
+
targets: []
|
|
156
223
|
};
|
|
224
|
+
const generateId = () => Math.random().toString(36).substring(2, 9);
|
|
157
225
|
const service = ({ strapi }) => ({
|
|
158
226
|
getWelcomeMessage() {
|
|
159
227
|
return "Welcome to Strapi Deployment Trigger";
|
|
@@ -176,35 +244,43 @@ const service = ({ strapi }) => ({
|
|
|
176
244
|
}
|
|
177
245
|
return { owner: null, repo: null };
|
|
178
246
|
},
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
247
|
+
// Migrate old single-config format to new multi-target format
|
|
248
|
+
migrateSettings(settings) {
|
|
249
|
+
if (!settings) return null;
|
|
250
|
+
if (Array.isArray(settings.targets)) {
|
|
251
|
+
return settings;
|
|
252
|
+
}
|
|
253
|
+
if (settings.workflow || settings.branch) {
|
|
185
254
|
return {
|
|
186
|
-
|
|
187
|
-
githubToken:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
255
|
+
repoUrl: settings.repoUrl || "",
|
|
256
|
+
githubToken: settings.githubToken || "",
|
|
257
|
+
targets: [{
|
|
258
|
+
id: generateId(),
|
|
259
|
+
name: "Default",
|
|
260
|
+
workflow: settings.workflow || "deploy.yml",
|
|
261
|
+
branch: settings.branch || "master"
|
|
262
|
+
}]
|
|
191
263
|
};
|
|
192
264
|
}
|
|
193
|
-
|
|
194
|
-
|
|
265
|
+
return settings;
|
|
266
|
+
},
|
|
267
|
+
async getSettings() {
|
|
268
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
269
|
+
let dbSettings = await store.get({ key: STORE_KEY });
|
|
270
|
+
dbSettings = this.migrateSettings(dbSettings);
|
|
271
|
+
if (!dbSettings) {
|
|
195
272
|
return {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
hasToken: !!envToken,
|
|
200
|
-
maskedToken: this.maskToken(envToken)
|
|
273
|
+
...DEFAULT_SETTINGS,
|
|
274
|
+
hasToken: false,
|
|
275
|
+
maskedToken: null
|
|
201
276
|
};
|
|
202
277
|
}
|
|
203
|
-
const token = dbSettings
|
|
278
|
+
const token = dbSettings.githubToken;
|
|
204
279
|
return {
|
|
205
|
-
|
|
206
|
-
|
|
280
|
+
repoUrl: dbSettings.repoUrl || "",
|
|
281
|
+
targets: dbSettings.targets || [],
|
|
207
282
|
githubToken: void 0,
|
|
283
|
+
// Never expose full token
|
|
208
284
|
hasToken: !!token,
|
|
209
285
|
maskedToken: this.maskToken(token)
|
|
210
286
|
};
|
|
@@ -212,33 +288,79 @@ const service = ({ strapi }) => ({
|
|
|
212
288
|
async saveSettings(settings) {
|
|
213
289
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
214
290
|
const existingSettings = await store.get({ key: STORE_KEY }) || {};
|
|
291
|
+
const migrated = this.migrateSettings(existingSettings);
|
|
215
292
|
const settingsToSave = {
|
|
216
|
-
repoUrl: settings.repoUrl,
|
|
217
|
-
|
|
218
|
-
branch: settings.branch || DEFAULT_SETTINGS.branch,
|
|
293
|
+
repoUrl: settings.repoUrl !== void 0 ? settings.repoUrl : migrated?.repoUrl || "",
|
|
294
|
+
targets: settings.targets !== void 0 ? settings.targets : migrated?.targets || [],
|
|
219
295
|
// Only update token if a new one is provided
|
|
220
|
-
githubToken: settings.githubToken ||
|
|
296
|
+
githubToken: settings.githubToken || migrated?.githubToken || ""
|
|
221
297
|
};
|
|
222
298
|
await store.set({ key: STORE_KEY, value: settingsToSave });
|
|
223
299
|
return {
|
|
224
|
-
|
|
300
|
+
repoUrl: settingsToSave.repoUrl,
|
|
301
|
+
targets: settingsToSave.targets,
|
|
225
302
|
githubToken: void 0,
|
|
226
|
-
hasToken: !!settingsToSave.githubToken
|
|
303
|
+
hasToken: !!settingsToSave.githubToken,
|
|
304
|
+
maskedToken: this.maskToken(settingsToSave.githubToken)
|
|
227
305
|
};
|
|
228
306
|
},
|
|
307
|
+
async addTarget(target) {
|
|
308
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
309
|
+
let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
|
|
310
|
+
settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
|
|
311
|
+
const newTarget = {
|
|
312
|
+
id: generateId(),
|
|
313
|
+
name: target.name || "New Target",
|
|
314
|
+
workflow: target.workflow || "deploy.yml",
|
|
315
|
+
branch: target.branch || "master"
|
|
316
|
+
};
|
|
317
|
+
settings.targets = [...settings.targets || [], newTarget];
|
|
318
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
319
|
+
return newTarget;
|
|
320
|
+
},
|
|
321
|
+
async updateTarget(targetId, updates) {
|
|
322
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
323
|
+
let settings = await store.get({ key: STORE_KEY });
|
|
324
|
+
settings = this.migrateSettings(settings);
|
|
325
|
+
if (!settings?.targets) return null;
|
|
326
|
+
const targetIndex = settings.targets.findIndex((t) => t.id === targetId);
|
|
327
|
+
if (targetIndex === -1) return null;
|
|
328
|
+
settings.targets[targetIndex] = {
|
|
329
|
+
...settings.targets[targetIndex],
|
|
330
|
+
...updates,
|
|
331
|
+
id: targetId
|
|
332
|
+
// Preserve ID
|
|
333
|
+
};
|
|
334
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
335
|
+
return settings.targets[targetIndex];
|
|
336
|
+
},
|
|
337
|
+
async deleteTarget(targetId) {
|
|
338
|
+
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
339
|
+
let settings = await store.get({ key: STORE_KEY });
|
|
340
|
+
settings = this.migrateSettings(settings);
|
|
341
|
+
if (!settings?.targets) return false;
|
|
342
|
+
const initialLength = settings.targets.length;
|
|
343
|
+
settings.targets = settings.targets.filter((t) => t.id !== targetId);
|
|
344
|
+
if (settings.targets.length === initialLength) return false;
|
|
345
|
+
await store.set({ key: STORE_KEY, value: settings });
|
|
346
|
+
return true;
|
|
347
|
+
},
|
|
348
|
+
async getTarget(targetId) {
|
|
349
|
+
const settings = await this.getSettings();
|
|
350
|
+
return settings.targets?.find((t) => t.id === targetId) || null;
|
|
351
|
+
},
|
|
229
352
|
async getToken() {
|
|
230
353
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
return process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
|
|
354
|
+
let dbSettings = await store.get({ key: STORE_KEY });
|
|
355
|
+
dbSettings = this.migrateSettings(dbSettings);
|
|
356
|
+
return dbSettings?.githubToken || null;
|
|
236
357
|
},
|
|
237
358
|
async isConfigured() {
|
|
238
359
|
const settings = await this.getSettings();
|
|
239
360
|
const hasToken = await this.getToken();
|
|
240
361
|
const { owner, repo } = this.parseRepoUrl(settings.repoUrl);
|
|
241
|
-
|
|
362
|
+
const hasTargets = settings.targets && settings.targets.length > 0;
|
|
363
|
+
return !!(owner && repo && hasToken && hasTargets);
|
|
242
364
|
},
|
|
243
365
|
async hasToken() {
|
|
244
366
|
const token = await this.getToken();
|
package/package.json
CHANGED
|
@@ -30,11 +30,45 @@ const controller = ({ strapi }) => ({
|
|
|
30
30
|
configured,
|
|
31
31
|
hasToken,
|
|
32
32
|
settings,
|
|
33
|
-
parsed: { owner, repo },
|
|
33
|
+
parsed: { owner, repo },
|
|
34
34
|
},
|
|
35
35
|
};
|
|
36
36
|
},
|
|
37
37
|
|
|
38
|
+
// Target CRUD operations
|
|
39
|
+
async addTarget(ctx) {
|
|
40
|
+
const { data } = ctx.request.body;
|
|
41
|
+
const service = getService(strapi);
|
|
42
|
+
const target = await service.addTarget(data);
|
|
43
|
+
ctx.body = { data: target };
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
async updateTarget(ctx) {
|
|
47
|
+
const { id } = ctx.params;
|
|
48
|
+
const { data } = ctx.request.body;
|
|
49
|
+
const service = getService(strapi);
|
|
50
|
+
const target = await service.updateTarget(id, data);
|
|
51
|
+
|
|
52
|
+
if (!target) {
|
|
53
|
+
return ctx.notFound('Target not found');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
ctx.body = { data: target };
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
async deleteTarget(ctx) {
|
|
60
|
+
const { id } = ctx.params;
|
|
61
|
+
const service = getService(strapi);
|
|
62
|
+
const deleted = await service.deleteTarget(id);
|
|
63
|
+
|
|
64
|
+
if (!deleted) {
|
|
65
|
+
return ctx.notFound('Target not found');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
ctx.body = { data: { success: true } };
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
// Trigger deployment for a specific target
|
|
38
72
|
async trigger(ctx) {
|
|
39
73
|
const service = getService(strapi);
|
|
40
74
|
const githubToken = await service.getToken();
|
|
@@ -50,7 +84,27 @@ const controller = ({ strapi }) => ({
|
|
|
50
84
|
return ctx.badRequest('GitHub repository URL is not configured or invalid. Please configure it in Settings.');
|
|
51
85
|
}
|
|
52
86
|
|
|
53
|
-
|
|
87
|
+
// Get target from request body or params
|
|
88
|
+
const { targetId, workflow: overrideWorkflow, branch: overrideBranch } = ctx.request.body || {};
|
|
89
|
+
|
|
90
|
+
let workflow, branch, targetName;
|
|
91
|
+
|
|
92
|
+
if (targetId) {
|
|
93
|
+
// Trigger specific target
|
|
94
|
+
const target = await service.getTarget(targetId);
|
|
95
|
+
if (!target) {
|
|
96
|
+
return ctx.badRequest('Target not found');
|
|
97
|
+
}
|
|
98
|
+
workflow = overrideWorkflow || target.workflow;
|
|
99
|
+
branch = overrideBranch || target.branch;
|
|
100
|
+
targetName = target.name;
|
|
101
|
+
} else {
|
|
102
|
+
// Fallback for backwards compatibility - use first target or provided values
|
|
103
|
+
const firstTarget = settings.targets?.[0];
|
|
104
|
+
workflow = overrideWorkflow || firstTarget?.workflow || 'deploy.yml';
|
|
105
|
+
branch = overrideBranch || firstTarget?.branch || 'master';
|
|
106
|
+
targetName = firstTarget?.name || 'Default';
|
|
107
|
+
}
|
|
54
108
|
|
|
55
109
|
const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
|
|
56
110
|
|
|
@@ -71,7 +125,7 @@ const controller = ({ strapi }) => ({
|
|
|
71
125
|
return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
|
|
72
126
|
}
|
|
73
127
|
|
|
74
|
-
strapi.log.info(`Deployment triggered for ${owner}/${repo} on branch ${branch}`);
|
|
128
|
+
strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
|
|
75
129
|
|
|
76
130
|
const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
|
|
77
131
|
|
|
@@ -80,6 +134,7 @@ const controller = ({ strapi }) => ({
|
|
|
80
134
|
success: true,
|
|
81
135
|
message: `Deployment triggered successfully for ${owner}/${repo}`,
|
|
82
136
|
repository: `${owner}/${repo}`,
|
|
137
|
+
targetName,
|
|
83
138
|
workflow,
|
|
84
139
|
branch,
|
|
85
140
|
actionsUrl,
|