@orange-soft/strapi-deployment-trigger 1.1.2 → 1.2.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.
@@ -68,6 +68,30 @@ const controller = ({ strapi }) => ({
68
68
  },
69
69
  // Trigger deployment for a specific target
70
70
  async trigger(ctx) {
71
+ const service2 = getService(strapi);
72
+ const { targetId } = ctx.request.body || {};
73
+ let target;
74
+ if (targetId) {
75
+ target = await service2.getTarget(targetId);
76
+ if (!target) {
77
+ return ctx.badRequest("Target not found");
78
+ }
79
+ } else {
80
+ const settings = await service2.getSettings();
81
+ target = settings.targets?.[0];
82
+ if (!target) {
83
+ return ctx.badRequest("No deployment targets configured");
84
+ }
85
+ }
86
+ const targetType = target.type || "github";
87
+ if (targetType === "vercel") {
88
+ return this.triggerVercel(ctx, target);
89
+ } else {
90
+ return this.triggerGitHub(ctx, target);
91
+ }
92
+ },
93
+ // Trigger GitHub Actions deployment
94
+ async triggerGitHub(ctx, target) {
71
95
  const service2 = getService(strapi);
72
96
  const githubToken = await service2.getToken();
73
97
  if (!githubToken) {
@@ -78,22 +102,9 @@ const controller = ({ strapi }) => ({
78
102
  if (!owner || !repo) {
79
103
  return ctx.badRequest("GitHub repository URL is not configured or invalid. Please configure it in Settings.");
80
104
  }
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
- }
105
+ const workflow = target.workflow || "deploy.yml";
106
+ const branch = target.branch || "master";
107
+ const targetName = target.name;
97
108
  const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
98
109
  try {
99
110
  const response = await fetch(url, {
@@ -110,11 +121,12 @@ const controller = ({ strapi }) => ({
110
121
  strapi.log.error(`GitHub API error: ${response.status} - ${errorText}`);
111
122
  return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
112
123
  }
113
- strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
124
+ strapi.log.info(`GitHub deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
114
125
  const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
115
126
  ctx.body = {
116
127
  data: {
117
128
  success: true,
129
+ type: "github",
118
130
  message: `Deployment triggered successfully for ${owner}/${repo}`,
119
131
  repository: `${owner}/${repo}`,
120
132
  targetName,
@@ -124,9 +136,39 @@ const controller = ({ strapi }) => ({
124
136
  }
125
137
  };
126
138
  } catch (error) {
127
- strapi.log.error("Error triggering deployment:", error);
139
+ strapi.log.error("Error triggering GitHub deployment:", error);
128
140
  return ctx.badRequest(`Failed to trigger deployment: ${error.message}`);
129
141
  }
142
+ },
143
+ // Trigger Vercel deployment via webhook
144
+ async triggerVercel(ctx, target) {
145
+ const webhookUrl = target.webhookUrl;
146
+ const targetName = target.name;
147
+ if (!webhookUrl) {
148
+ return ctx.badRequest("Vercel webhook URL is not configured for this target.");
149
+ }
150
+ try {
151
+ const response = await fetch(webhookUrl, {
152
+ method: "POST"
153
+ });
154
+ if (!response.ok) {
155
+ const errorText = await response.text();
156
+ strapi.log.error(`Vercel webhook error: ${response.status} - ${errorText}`);
157
+ return ctx.badRequest(`Vercel webhook error: ${response.status} - ${errorText}`);
158
+ }
159
+ strapi.log.info(`Vercel deployment triggered [${targetName}]`);
160
+ ctx.body = {
161
+ data: {
162
+ success: true,
163
+ type: "vercel",
164
+ message: "Vercel deployment triggered successfully",
165
+ targetName
166
+ }
167
+ };
168
+ } catch (error) {
169
+ strapi.log.error("Error triggering Vercel deployment:", error);
170
+ return ctx.badRequest(`Failed to trigger Vercel deployment: ${error.message}`);
171
+ }
130
172
  }
131
173
  });
132
174
  const controllers = {
@@ -248,7 +290,14 @@ const service = ({ strapi }) => ({
248
290
  migrateSettings(settings) {
249
291
  if (!settings) return null;
250
292
  if (Array.isArray(settings.targets)) {
251
- return settings;
293
+ const targetsWithType = settings.targets.map((target) => ({
294
+ ...target,
295
+ type: target.type || "github"
296
+ }));
297
+ return {
298
+ ...settings,
299
+ targets: targetsWithType
300
+ };
252
301
  }
253
302
  if (settings.workflow || settings.branch) {
254
303
  return {
@@ -256,6 +305,7 @@ const service = ({ strapi }) => ({
256
305
  githubToken: settings.githubToken || "",
257
306
  targets: [{
258
307
  id: generateId(),
308
+ type: "github",
259
309
  name: "Default",
260
310
  workflow: settings.workflow || "deploy.yml",
261
311
  branch: settings.branch || "master"
@@ -312,12 +362,18 @@ const service = ({ strapi }) => ({
312
362
  const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
313
363
  let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
314
364
  settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
365
+ const targetType = target.type || "github";
315
366
  const newTarget = {
316
367
  id: generateId(),
317
- name: target.name || "New Target",
318
- workflow: target.workflow || "deploy.yml",
319
- branch: target.branch || "master"
368
+ type: targetType,
369
+ name: target.name || "New Target"
320
370
  };
371
+ if (targetType === "github") {
372
+ newTarget.workflow = target.workflow || "deploy.yml";
373
+ newTarget.branch = target.branch || "master";
374
+ } else if (targetType === "vercel") {
375
+ newTarget.webhookUrl = target.webhookUrl || "";
376
+ }
321
377
  settings.targets = [...settings.targets || [], newTarget];
322
378
  await store.set({ key: STORE_KEY, value: settings });
323
379
  return newTarget;
@@ -329,12 +385,20 @@ const service = ({ strapi }) => ({
329
385
  if (!settings?.targets) return null;
330
386
  const targetIndex = settings.targets.findIndex((t) => t.id === targetId);
331
387
  if (targetIndex === -1) return null;
332
- settings.targets[targetIndex] = {
333
- ...settings.targets[targetIndex],
334
- ...updates,
335
- id: targetId
336
- // Preserve ID
388
+ const existingTarget = settings.targets[targetIndex];
389
+ const targetType = updates.type || existingTarget.type || "github";
390
+ const updatedTarget = {
391
+ id: targetId,
392
+ type: targetType,
393
+ name: updates.name !== void 0 ? updates.name : existingTarget.name
337
394
  };
395
+ if (targetType === "github") {
396
+ updatedTarget.workflow = updates.workflow !== void 0 ? updates.workflow : existingTarget.workflow;
397
+ updatedTarget.branch = updates.branch !== void 0 ? updates.branch : existingTarget.branch;
398
+ } else if (targetType === "vercel") {
399
+ updatedTarget.webhookUrl = updates.webhookUrl !== void 0 ? updates.webhookUrl : existingTarget.webhookUrl;
400
+ }
401
+ settings.targets[targetIndex] = updatedTarget;
338
402
  await store.set({ key: STORE_KEY, value: settings });
339
403
  return settings.targets[targetIndex];
340
404
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orange-soft/strapi-deployment-trigger",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Strapi v5 plugin to trigger GitHub Actions workflow deployments from the admin panel",
5
5
  "license": "MIT",
6
6
  "author": "Justin Moh <moh@os.my>",
@@ -70,6 +70,37 @@ const controller = ({ strapi }) => ({
70
70
 
71
71
  // Trigger deployment for a specific target
72
72
  async trigger(ctx) {
73
+ const service = getService(strapi);
74
+ const { targetId } = ctx.request.body || {};
75
+
76
+ // Get target
77
+ let target;
78
+ if (targetId) {
79
+ target = await service.getTarget(targetId);
80
+ if (!target) {
81
+ return ctx.badRequest('Target not found');
82
+ }
83
+ } else {
84
+ // Fallback for backwards compatibility - use first target
85
+ const settings = await service.getSettings();
86
+ target = settings.targets?.[0];
87
+ if (!target) {
88
+ return ctx.badRequest('No deployment targets configured');
89
+ }
90
+ }
91
+
92
+ const targetType = target.type || 'github';
93
+
94
+ // Branch by target type
95
+ if (targetType === 'vercel') {
96
+ return this.triggerVercel(ctx, target);
97
+ } else {
98
+ return this.triggerGitHub(ctx, target);
99
+ }
100
+ },
101
+
102
+ // Trigger GitHub Actions deployment
103
+ async triggerGitHub(ctx, target) {
73
104
  const service = getService(strapi);
74
105
  const githubToken = await service.getToken();
75
106
 
@@ -84,27 +115,9 @@ const controller = ({ strapi }) => ({
84
115
  return ctx.badRequest('GitHub repository URL is not configured or invalid. Please configure it in Settings.');
85
116
  }
86
117
 
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
- }
118
+ const workflow = target.workflow || 'deploy.yml';
119
+ const branch = target.branch || 'master';
120
+ const targetName = target.name;
108
121
 
109
122
  const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
110
123
 
@@ -125,13 +138,14 @@ const controller = ({ strapi }) => ({
125
138
  return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
126
139
  }
127
140
 
128
- strapi.log.info(`Deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
141
+ strapi.log.info(`GitHub deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
129
142
 
130
143
  const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
131
144
 
132
145
  ctx.body = {
133
146
  data: {
134
147
  success: true,
148
+ type: 'github',
135
149
  message: `Deployment triggered successfully for ${owner}/${repo}`,
136
150
  repository: `${owner}/${repo}`,
137
151
  targetName,
@@ -141,10 +155,46 @@ const controller = ({ strapi }) => ({
141
155
  },
142
156
  };
143
157
  } catch (error) {
144
- strapi.log.error('Error triggering deployment:', error);
158
+ strapi.log.error('Error triggering GitHub deployment:', error);
145
159
  return ctx.badRequest(`Failed to trigger deployment: ${error.message}`);
146
160
  }
147
161
  },
162
+
163
+ // Trigger Vercel deployment via webhook
164
+ async triggerVercel(ctx, target) {
165
+ const webhookUrl = target.webhookUrl;
166
+ const targetName = target.name;
167
+
168
+ if (!webhookUrl) {
169
+ return ctx.badRequest('Vercel webhook URL is not configured for this target.');
170
+ }
171
+
172
+ try {
173
+ const response = await fetch(webhookUrl, {
174
+ method: 'POST',
175
+ });
176
+
177
+ if (!response.ok) {
178
+ const errorText = await response.text();
179
+ strapi.log.error(`Vercel webhook error: ${response.status} - ${errorText}`);
180
+ return ctx.badRequest(`Vercel webhook error: ${response.status} - ${errorText}`);
181
+ }
182
+
183
+ strapi.log.info(`Vercel deployment triggered [${targetName}]`);
184
+
185
+ ctx.body = {
186
+ data: {
187
+ success: true,
188
+ type: 'vercel',
189
+ message: 'Vercel deployment triggered successfully',
190
+ targetName,
191
+ },
192
+ };
193
+ } catch (error) {
194
+ strapi.log.error('Error triggering Vercel deployment:', error);
195
+ return ctx.badRequest(`Failed to trigger Vercel deployment: ${error.message}`);
196
+ }
197
+ },
148
198
  });
149
199
 
150
200
  export default controller;
@@ -39,9 +39,17 @@ const service = ({ strapi }) => ({
39
39
  migrateSettings(settings) {
40
40
  if (!settings) return null;
41
41
 
42
- // Already in new format
42
+ // Already in new format with targets array
43
43
  if (Array.isArray(settings.targets)) {
44
- return settings;
44
+ // Ensure all targets have a type field (backward compatibility)
45
+ const targetsWithType = settings.targets.map(target => ({
46
+ ...target,
47
+ type: target.type || 'github',
48
+ }));
49
+ return {
50
+ ...settings,
51
+ targets: targetsWithType,
52
+ };
45
53
  }
46
54
 
47
55
  // Old format detected - migrate
@@ -51,6 +59,7 @@ const service = ({ strapi }) => ({
51
59
  githubToken: settings.githubToken || '',
52
60
  targets: [{
53
61
  id: generateId(),
62
+ type: 'github',
54
63
  name: 'Default',
55
64
  workflow: settings.workflow || 'deploy.yml',
56
65
  branch: settings.branch || 'master',
@@ -124,13 +133,22 @@ const service = ({ strapi }) => ({
124
133
  let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
125
134
  settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
126
135
 
136
+ const targetType = target.type || 'github';
137
+
127
138
  const newTarget = {
128
139
  id: generateId(),
140
+ type: targetType,
129
141
  name: target.name || 'New Target',
130
- workflow: target.workflow || 'deploy.yml',
131
- branch: target.branch || 'master',
132
142
  };
133
143
 
144
+ // Add type-specific fields
145
+ if (targetType === 'github') {
146
+ newTarget.workflow = target.workflow || 'deploy.yml';
147
+ newTarget.branch = target.branch || 'master';
148
+ } else if (targetType === 'vercel') {
149
+ newTarget.webhookUrl = target.webhookUrl || '';
150
+ }
151
+
134
152
  settings.targets = [...(settings.targets || []), newTarget];
135
153
  await store.set({ key: STORE_KEY, value: settings });
136
154
 
@@ -147,12 +165,25 @@ const service = ({ strapi }) => ({
147
165
  const targetIndex = settings.targets.findIndex(t => t.id === targetId);
148
166
  if (targetIndex === -1) return null;
149
167
 
150
- settings.targets[targetIndex] = {
151
- ...settings.targets[targetIndex],
152
- ...updates,
153
- id: targetId, // Preserve ID
168
+ const existingTarget = settings.targets[targetIndex];
169
+ const targetType = updates.type || existingTarget.type || 'github';
170
+
171
+ // Build updated target with type-specific fields
172
+ const updatedTarget = {
173
+ id: targetId,
174
+ type: targetType,
175
+ name: updates.name !== undefined ? updates.name : existingTarget.name,
154
176
  };
155
177
 
178
+ if (targetType === 'github') {
179
+ updatedTarget.workflow = updates.workflow !== undefined ? updates.workflow : existingTarget.workflow;
180
+ updatedTarget.branch = updates.branch !== undefined ? updates.branch : existingTarget.branch;
181
+ } else if (targetType === 'vercel') {
182
+ updatedTarget.webhookUrl = updates.webhookUrl !== undefined ? updates.webhookUrl : existingTarget.webhookUrl;
183
+ }
184
+
185
+ settings.targets[targetIndex] = updatedTarget;
186
+
156
187
  await store.set({ key: STORE_KEY, value: settings });
157
188
  return settings.targets[targetIndex];
158
189
  },