@orange-soft/strapi-deployment-trigger 1.1.0 → 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.
- package/README.md +34 -13
- package/admin/src/pages/HomePage.jsx +67 -33
- package/admin/src/pages/SettingsPage.jsx +143 -68
- package/dist/_chunks/{App-vakyp6FE.mjs → App-k07qAAvE.mjs} +165 -90
- package/dist/_chunks/{App-CuSCtdH7.js → App-vIrt97zQ.js} +162 -87
- package/dist/_chunks/{index-CZWWYGR3.mjs → index-BwZtnn__.mjs} +1 -1
- package/dist/_chunks/{index-DGatQB-9.js → index-w-vQ80Px.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +95 -27
- package/dist/server/index.mjs +95 -27
- package/package.json +1 -1
- package/server/src/controllers/controller.js +73 -23
- package/server/src/services/service.js +47 -8
|
@@ -7,17 +7,22 @@ const react = require("react");
|
|
|
7
7
|
const reactIntl = require("react-intl");
|
|
8
8
|
const designSystem = require("@strapi/design-system");
|
|
9
9
|
const icons = require("@strapi/icons");
|
|
10
|
-
const index = require("./index-
|
|
10
|
+
const index = require("./index-w-vQ80Px.js");
|
|
11
11
|
const getTranslation = (id) => `${index.PLUGIN_ID}.${id}`;
|
|
12
12
|
const HomePage = () => {
|
|
13
13
|
const { formatMessage } = reactIntl.useIntl();
|
|
14
14
|
const { get, post } = admin.useFetchClient();
|
|
15
|
+
const location = reactRouterDom.useLocation();
|
|
15
16
|
const [status, setStatus] = react.useState(null);
|
|
16
17
|
const [loading, setLoading] = react.useState(true);
|
|
17
18
|
const [deployingTargetId, setDeployingTargetId] = react.useState(null);
|
|
18
19
|
const [notification, setNotification] = react.useState(null);
|
|
19
20
|
react.useEffect(() => {
|
|
20
21
|
fetchStatus();
|
|
22
|
+
if (location.state?.notification) {
|
|
23
|
+
setNotification(location.state.notification);
|
|
24
|
+
window.history.replaceState({}, document.title);
|
|
25
|
+
}
|
|
21
26
|
}, []);
|
|
22
27
|
const fetchStatus = async () => {
|
|
23
28
|
try {
|
|
@@ -62,9 +67,18 @@ const HomePage = () => {
|
|
|
62
67
|
}
|
|
63
68
|
const settings = status?.settings || {};
|
|
64
69
|
const parsed = status?.parsed || {};
|
|
65
|
-
|
|
70
|
+
status?.configured;
|
|
66
71
|
const hasToken = status?.hasToken;
|
|
67
72
|
const targets = settings.targets || [];
|
|
73
|
+
const hasGitHubTargets = targets.some((t) => (t.type || "github") === "github");
|
|
74
|
+
targets.some((t) => t.type === "vercel");
|
|
75
|
+
const canTrigger = (target) => {
|
|
76
|
+
const targetType = target.type || "github";
|
|
77
|
+
if (targetType === "github") {
|
|
78
|
+
return hasToken && parsed.owner && parsed.repo;
|
|
79
|
+
}
|
|
80
|
+
return !!target.webhookUrl;
|
|
81
|
+
};
|
|
68
82
|
return /* @__PURE__ */ jsxRuntime.jsxs(admin.Layouts.Root, { children: [
|
|
69
83
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70
84
|
admin.Layouts.Header,
|
|
@@ -100,8 +114,8 @@ const HomePage = () => {
|
|
|
100
114
|
] })
|
|
101
115
|
}
|
|
102
116
|
) }),
|
|
103
|
-
!hasToken && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Token Missing", variant: "danger", children: "GitHub Personal Access Token is not configured. Please add it in Settings." }) }),
|
|
104
|
-
!settings.repoUrl && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Configuration Required", variant: "warning", children: "Please configure your GitHub repository in the Settings page before triggering deployments." }) }),
|
|
117
|
+
hasGitHubTargets && !hasToken && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Token Missing", variant: "danger", children: "GitHub Personal Access Token is not configured. Please add it in Settings." }) }),
|
|
118
|
+
hasGitHubTargets && !settings.repoUrl && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Alert, { title: "Configuration Required", variant: "warning", children: "Please configure your GitHub repository in the Settings page before triggering deployments." }) }),
|
|
105
119
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
106
120
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
107
121
|
designSystem.Box,
|
|
@@ -154,27 +168,34 @@ const HomePage = () => {
|
|
|
154
168
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: "Deployment Targets" }),
|
|
155
169
|
targets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
|
|
156
170
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Type" }) }),
|
|
157
172
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Name" }) }),
|
|
158
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "
|
|
159
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Branch" }) }),
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Details" }) }),
|
|
160
174
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Action" }) })
|
|
161
175
|
] }) }),
|
|
162
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: targets.map((target) =>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
designSystem.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: targets.map((target) => {
|
|
177
|
+
const targetType = target.type || "github";
|
|
178
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", textColor: targetType === "github" ? "neutral800" : "secondary600", children: targetType === "github" ? "GitHub" : "Vercel" }) }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: target.name }) }),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: targetType === "github" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: [
|
|
182
|
+
target.workflow,
|
|
183
|
+
" / ",
|
|
184
|
+
target.branch
|
|
185
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Webhook" }) }),
|
|
186
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
187
|
+
designSystem.Button,
|
|
188
|
+
{
|
|
189
|
+
onClick: () => handleDeploy(target.id, target.name),
|
|
190
|
+
loading: deployingTargetId === target.id,
|
|
191
|
+
disabled: !canTrigger(target) || deployingTargetId !== null,
|
|
192
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Rocket, {}),
|
|
193
|
+
size: "S",
|
|
194
|
+
children: deployingTargetId === target.id ? "Triggering..." : "Trigger"
|
|
195
|
+
}
|
|
196
|
+
) })
|
|
197
|
+
] }, target.id);
|
|
198
|
+
}) })
|
|
178
199
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", gap: 3, padding: 6, children: [
|
|
179
200
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "No deployment targets configured" }),
|
|
180
201
|
/* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/plugins/${index.PLUGIN_ID}/settings`, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "default", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cog, {}), children: "Add Targets in Settings" }) })
|
|
@@ -182,7 +203,7 @@ const HomePage = () => {
|
|
|
182
203
|
] })
|
|
183
204
|
}
|
|
184
205
|
),
|
|
185
|
-
|
|
206
|
+
hasGitHubTargets && (!hasToken || !parsed.owner || !parsed.repo) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
186
207
|
designSystem.Box,
|
|
187
208
|
{
|
|
188
209
|
background: "neutral0",
|
|
@@ -193,8 +214,8 @@ const HomePage = () => {
|
|
|
193
214
|
paddingLeft: 7,
|
|
194
215
|
paddingRight: 7,
|
|
195
216
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", gap: 3, children: [
|
|
196
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", textColor: "neutral600", textAlign: "center", children: "Setup Incomplete" }),
|
|
197
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "Please ensure repository URL and GitHub token are configured in Settings." }),
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", textColor: "neutral600", textAlign: "center", children: "GitHub Setup Incomplete" }),
|
|
218
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", textAlign: "center", children: "Please ensure repository URL and GitHub token are configured in Settings for GitHub targets." }),
|
|
198
219
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: `/plugins/${index.PLUGIN_ID}/settings`, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "default", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Cog, {}), children: "Go to Settings" }) }) })
|
|
199
220
|
] })
|
|
200
221
|
}
|
|
@@ -206,6 +227,7 @@ const HomePage = () => {
|
|
|
206
227
|
const TOKEN_PATTERN = /^github_pat_[a-zA-Z0-9_]+$/;
|
|
207
228
|
const REPO_URL_PATTERN = /^https:\/\/github\.com\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+\/?$/;
|
|
208
229
|
const WORKFLOW_PATTERN = /^[a-zA-Z0-9_.-]+\.ya?ml$/;
|
|
230
|
+
const VERCEL_WEBHOOK_PATTERN = /^https:\/\/api\.vercel\.com\/v1\/integrations\/deploy\/.+$/;
|
|
209
231
|
const validateToken = (value) => {
|
|
210
232
|
if (!value) return null;
|
|
211
233
|
if (!TOKEN_PATTERN.test(value)) {
|
|
@@ -227,7 +249,15 @@ const validateWorkflow = (value) => {
|
|
|
227
249
|
}
|
|
228
250
|
return null;
|
|
229
251
|
};
|
|
252
|
+
const validateVercelWebhook = (value) => {
|
|
253
|
+
if (!value) return "Webhook URL is required";
|
|
254
|
+
if (!VERCEL_WEBHOOK_PATTERN.test(value)) {
|
|
255
|
+
return "Must be a valid Vercel deploy hook URL (https://api.vercel.com/v1/integrations/deploy/...)";
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
};
|
|
230
259
|
const SettingsPage = () => {
|
|
260
|
+
const navigate = reactRouterDom.useNavigate();
|
|
231
261
|
const { get, put, post, del } = admin.useFetchClient();
|
|
232
262
|
const [settings, setSettings] = react.useState({
|
|
233
263
|
githubToken: "",
|
|
@@ -241,7 +271,7 @@ const SettingsPage = () => {
|
|
|
241
271
|
const [saving, setSaving] = react.useState(false);
|
|
242
272
|
const [notification, setNotification] = react.useState(null);
|
|
243
273
|
const [editingTarget, setEditingTarget] = react.useState(null);
|
|
244
|
-
const [targetForm, setTargetForm] = react.useState({ name: "", workflow: "", branch: "" });
|
|
274
|
+
const [targetForm, setTargetForm] = react.useState({ type: "github", name: "", workflow: "", branch: "", webhookUrl: "" });
|
|
245
275
|
const [targetErrors, setTargetErrors] = react.useState({});
|
|
246
276
|
const [showAddForm, setShowAddForm] = react.useState(false);
|
|
247
277
|
const [deleteDialogOpen, setDeleteDialogOpen] = react.useState(false);
|
|
@@ -288,17 +318,14 @@ const SettingsPage = () => {
|
|
|
288
318
|
dataToSave.githubToken = settings.githubToken;
|
|
289
319
|
}
|
|
290
320
|
const { data } = await put(`/${index.PLUGIN_ID}/settings`, { data: dataToSave });
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
setSettings((prev) => ({ ...prev, githubToken: "" }));
|
|
296
|
-
setNotification({ type: "success", message: "Settings saved successfully" });
|
|
321
|
+
navigate(`/plugins/${index.PLUGIN_ID}`, {
|
|
322
|
+
state: { notification: { type: "success", message: "Settings saved successfully" } }
|
|
323
|
+
});
|
|
297
324
|
} catch (error) {
|
|
298
325
|
console.error("Error saving settings:", error);
|
|
299
326
|
setNotification({ type: "danger", message: "Failed to save settings" });
|
|
327
|
+
setSaving(false);
|
|
300
328
|
}
|
|
301
|
-
setSaving(false);
|
|
302
329
|
};
|
|
303
330
|
const handleChange = (field) => (e) => {
|
|
304
331
|
const value = e.target.value;
|
|
@@ -308,7 +335,7 @@ const SettingsPage = () => {
|
|
|
308
335
|
}
|
|
309
336
|
};
|
|
310
337
|
const resetTargetForm = () => {
|
|
311
|
-
setTargetForm({ name: "", workflow: "deploy.yml", branch: "master" });
|
|
338
|
+
setTargetForm({ type: "github", name: "", workflow: "deploy.yml", branch: "master", webhookUrl: "" });
|
|
312
339
|
setTargetErrors({});
|
|
313
340
|
setEditingTarget(null);
|
|
314
341
|
setShowAddForm(false);
|
|
@@ -316,9 +343,14 @@ const SettingsPage = () => {
|
|
|
316
343
|
const validateTargetForm = () => {
|
|
317
344
|
const newErrors = {};
|
|
318
345
|
if (!targetForm.name.trim()) newErrors.name = "Name is required";
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
346
|
+
if (targetForm.type === "github") {
|
|
347
|
+
const workflowError = validateWorkflow(targetForm.workflow);
|
|
348
|
+
if (workflowError) newErrors.workflow = workflowError;
|
|
349
|
+
if (!targetForm.branch.trim()) newErrors.branch = "Branch is required";
|
|
350
|
+
} else if (targetForm.type === "vercel") {
|
|
351
|
+
const webhookError = validateVercelWebhook(targetForm.webhookUrl);
|
|
352
|
+
if (webhookError) newErrors.webhookUrl = webhookError;
|
|
353
|
+
}
|
|
322
354
|
setTargetErrors(newErrors);
|
|
323
355
|
return Object.keys(newErrors).length === 0;
|
|
324
356
|
};
|
|
@@ -339,7 +371,13 @@ const SettingsPage = () => {
|
|
|
339
371
|
};
|
|
340
372
|
const handleEditTarget = (target) => {
|
|
341
373
|
setEditingTarget(target.id);
|
|
342
|
-
setTargetForm({
|
|
374
|
+
setTargetForm({
|
|
375
|
+
type: target.type || "github",
|
|
376
|
+
name: target.name,
|
|
377
|
+
workflow: target.workflow || "deploy.yml",
|
|
378
|
+
branch: target.branch || "master",
|
|
379
|
+
webhookUrl: target.webhookUrl || ""
|
|
380
|
+
});
|
|
343
381
|
setShowAddForm(false);
|
|
344
382
|
};
|
|
345
383
|
const handleUpdateTarget = async () => {
|
|
@@ -481,7 +519,7 @@ const SettingsPage = () => {
|
|
|
481
519
|
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
|
|
482
520
|
onClick: () => {
|
|
483
521
|
setShowAddForm(true);
|
|
484
|
-
setTargetForm({ name: "", workflow: "deploy.yml", branch: "master" });
|
|
522
|
+
setTargetForm({ type: "github", name: "", workflow: "deploy.yml", branch: "master", webhookUrl: "" });
|
|
485
523
|
},
|
|
486
524
|
size: "S",
|
|
487
525
|
children: "Add Target"
|
|
@@ -497,7 +535,21 @@ const SettingsPage = () => {
|
|
|
497
535
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, children: [
|
|
498
536
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: editingTarget ? "Edit Target" : "Add New Target" }),
|
|
499
537
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
|
|
500
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col:
|
|
538
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetType", required: true, children: [
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Type" }),
|
|
540
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
541
|
+
designSystem.SingleSelect,
|
|
542
|
+
{
|
|
543
|
+
value: targetForm.type,
|
|
544
|
+
onChange: (value) => setTargetForm((prev) => ({ ...prev, type: value })),
|
|
545
|
+
children: [
|
|
546
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "github", children: "GitHub" }),
|
|
547
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "vercel", children: "Vercel" })
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
] }) }),
|
|
552
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetName", required: true, error: targetErrors.name, children: [
|
|
501
553
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Name" }),
|
|
502
554
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
503
555
|
designSystem.Field.Input,
|
|
@@ -509,26 +561,40 @@ const SettingsPage = () => {
|
|
|
509
561
|
),
|
|
510
562
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
511
563
|
] }) }),
|
|
512
|
-
|
|
513
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.
|
|
564
|
+
targetForm.type === "github" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
565
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetWorkflow", required: true, error: targetErrors.workflow, children: [
|
|
566
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Workflow File" }),
|
|
567
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
568
|
+
designSystem.Field.Input,
|
|
569
|
+
{
|
|
570
|
+
placeholder: "deploy.yml",
|
|
571
|
+
value: targetForm.workflow,
|
|
572
|
+
onChange: handleTargetFormChange("workflow")
|
|
573
|
+
}
|
|
574
|
+
),
|
|
575
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
576
|
+
] }) }),
|
|
577
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetBranch", required: true, error: targetErrors.branch, children: [
|
|
578
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Branch" }),
|
|
579
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
580
|
+
designSystem.Field.Input,
|
|
581
|
+
{
|
|
582
|
+
placeholder: "main",
|
|
583
|
+
value: targetForm.branch,
|
|
584
|
+
onChange: handleTargetFormChange("branch")
|
|
585
|
+
}
|
|
586
|
+
),
|
|
587
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
588
|
+
] }) })
|
|
589
|
+
] }),
|
|
590
|
+
targetForm.type === "vercel" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "targetWebhookUrl", required: true, error: targetErrors.webhookUrl, children: [
|
|
591
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Webhook URL" }),
|
|
526
592
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
527
593
|
designSystem.Field.Input,
|
|
528
594
|
{
|
|
529
|
-
placeholder: "
|
|
530
|
-
value: targetForm.
|
|
531
|
-
onChange: handleTargetFormChange("
|
|
595
|
+
placeholder: "https://api.vercel.com/v1/integrations/deploy/...",
|
|
596
|
+
value: targetForm.webhookUrl,
|
|
597
|
+
onChange: handleTargetFormChange("webhookUrl")
|
|
532
598
|
}
|
|
533
599
|
),
|
|
534
600
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {})
|
|
@@ -550,39 +616,48 @@ const SettingsPage = () => {
|
|
|
550
616
|
),
|
|
551
617
|
settings.targets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { children: [
|
|
552
618
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
619
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Type" }) }),
|
|
553
620
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Name" }) }),
|
|
554
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "
|
|
555
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Branch" }) }),
|
|
621
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Details" }) }),
|
|
556
622
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Actions" }) })
|
|
557
623
|
] }) }),
|
|
558
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: settings.targets.map((target) =>
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
624
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: settings.targets.map((target) => {
|
|
625
|
+
const targetType = target.type || "github";
|
|
626
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
627
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", textColor: targetType === "github" ? "neutral800" : "secondary600", children: targetType === "github" ? "GitHub" : "Vercel" }) }),
|
|
628
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: target.name }) }),
|
|
629
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: targetType === "github" ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: [
|
|
630
|
+
target.workflow,
|
|
631
|
+
" / ",
|
|
632
|
+
target.branch
|
|
633
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Webhook configured" }) }),
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
635
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
636
|
+
designSystem.Button,
|
|
637
|
+
{
|
|
638
|
+
onClick: () => handleEditTarget(target),
|
|
639
|
+
variant: "tertiary",
|
|
640
|
+
size: "S",
|
|
641
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}),
|
|
642
|
+
children: "Edit"
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
646
|
+
designSystem.Button,
|
|
647
|
+
{
|
|
648
|
+
onClick: () => {
|
|
649
|
+
setTargetToDelete(target.id);
|
|
650
|
+
setDeleteDialogOpen(true);
|
|
651
|
+
},
|
|
652
|
+
variant: "danger-light",
|
|
653
|
+
size: "S",
|
|
654
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}),
|
|
655
|
+
children: "Delete"
|
|
656
|
+
}
|
|
657
|
+
)
|
|
658
|
+
] }) })
|
|
659
|
+
] }, target.id);
|
|
660
|
+
}) })
|
|
586
661
|
] }) : !showAddForm && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: 'No deployment targets configured. Click "Add Target" to create one.' })
|
|
587
662
|
] })
|
|
588
663
|
}
|
|
@@ -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-vIrt97zQ.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
|
@@ -69,6 +69,30 @@ const controller = ({ strapi }) => ({
|
|
|
69
69
|
},
|
|
70
70
|
// Trigger deployment for a specific target
|
|
71
71
|
async trigger(ctx) {
|
|
72
|
+
const service2 = getService(strapi);
|
|
73
|
+
const { targetId } = ctx.request.body || {};
|
|
74
|
+
let target;
|
|
75
|
+
if (targetId) {
|
|
76
|
+
target = await service2.getTarget(targetId);
|
|
77
|
+
if (!target) {
|
|
78
|
+
return ctx.badRequest("Target not found");
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
const settings = await service2.getSettings();
|
|
82
|
+
target = settings.targets?.[0];
|
|
83
|
+
if (!target) {
|
|
84
|
+
return ctx.badRequest("No deployment targets configured");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const targetType = target.type || "github";
|
|
88
|
+
if (targetType === "vercel") {
|
|
89
|
+
return this.triggerVercel(ctx, target);
|
|
90
|
+
} else {
|
|
91
|
+
return this.triggerGitHub(ctx, target);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
// Trigger GitHub Actions deployment
|
|
95
|
+
async triggerGitHub(ctx, target) {
|
|
72
96
|
const service2 = getService(strapi);
|
|
73
97
|
const githubToken = await service2.getToken();
|
|
74
98
|
if (!githubToken) {
|
|
@@ -79,22 +103,9 @@ const controller = ({ strapi }) => ({
|
|
|
79
103
|
if (!owner || !repo) {
|
|
80
104
|
return ctx.badRequest("GitHub repository URL is not configured or invalid. Please configure it in Settings.");
|
|
81
105
|
}
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
}
|
|
106
|
+
const workflow = target.workflow || "deploy.yml";
|
|
107
|
+
const branch = target.branch || "master";
|
|
108
|
+
const targetName = target.name;
|
|
98
109
|
const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`;
|
|
99
110
|
try {
|
|
100
111
|
const response = await fetch(url, {
|
|
@@ -111,11 +122,12 @@ const controller = ({ strapi }) => ({
|
|
|
111
122
|
strapi.log.error(`GitHub API error: ${response.status} - ${errorText}`);
|
|
112
123
|
return ctx.badRequest(`GitHub API error: ${response.status} - ${errorText}`);
|
|
113
124
|
}
|
|
114
|
-
strapi.log.info(`
|
|
125
|
+
strapi.log.info(`GitHub deployment triggered for ${owner}/${repo} [${targetName}] on branch ${branch}`);
|
|
115
126
|
const actionsUrl = `https://github.com/${owner}/${repo}/actions`;
|
|
116
127
|
ctx.body = {
|
|
117
128
|
data: {
|
|
118
129
|
success: true,
|
|
130
|
+
type: "github",
|
|
119
131
|
message: `Deployment triggered successfully for ${owner}/${repo}`,
|
|
120
132
|
repository: `${owner}/${repo}`,
|
|
121
133
|
targetName,
|
|
@@ -125,9 +137,39 @@ const controller = ({ strapi }) => ({
|
|
|
125
137
|
}
|
|
126
138
|
};
|
|
127
139
|
} catch (error) {
|
|
128
|
-
strapi.log.error("Error triggering deployment:", error);
|
|
140
|
+
strapi.log.error("Error triggering GitHub deployment:", error);
|
|
129
141
|
return ctx.badRequest(`Failed to trigger deployment: ${error.message}`);
|
|
130
142
|
}
|
|
143
|
+
},
|
|
144
|
+
// Trigger Vercel deployment via webhook
|
|
145
|
+
async triggerVercel(ctx, target) {
|
|
146
|
+
const webhookUrl = target.webhookUrl;
|
|
147
|
+
const targetName = target.name;
|
|
148
|
+
if (!webhookUrl) {
|
|
149
|
+
return ctx.badRequest("Vercel webhook URL is not configured for this target.");
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const response = await fetch(webhookUrl, {
|
|
153
|
+
method: "POST"
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
const errorText = await response.text();
|
|
157
|
+
strapi.log.error(`Vercel webhook error: ${response.status} - ${errorText}`);
|
|
158
|
+
return ctx.badRequest(`Vercel webhook error: ${response.status} - ${errorText}`);
|
|
159
|
+
}
|
|
160
|
+
strapi.log.info(`Vercel deployment triggered [${targetName}]`);
|
|
161
|
+
ctx.body = {
|
|
162
|
+
data: {
|
|
163
|
+
success: true,
|
|
164
|
+
type: "vercel",
|
|
165
|
+
message: "Vercel deployment triggered successfully",
|
|
166
|
+
targetName
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
} catch (error) {
|
|
170
|
+
strapi.log.error("Error triggering Vercel deployment:", error);
|
|
171
|
+
return ctx.badRequest(`Failed to trigger Vercel deployment: ${error.message}`);
|
|
172
|
+
}
|
|
131
173
|
}
|
|
132
174
|
});
|
|
133
175
|
const controllers = {
|
|
@@ -249,7 +291,14 @@ const service = ({ strapi }) => ({
|
|
|
249
291
|
migrateSettings(settings) {
|
|
250
292
|
if (!settings) return null;
|
|
251
293
|
if (Array.isArray(settings.targets)) {
|
|
252
|
-
|
|
294
|
+
const targetsWithType = settings.targets.map((target) => ({
|
|
295
|
+
...target,
|
|
296
|
+
type: target.type || "github"
|
|
297
|
+
}));
|
|
298
|
+
return {
|
|
299
|
+
...settings,
|
|
300
|
+
targets: targetsWithType
|
|
301
|
+
};
|
|
253
302
|
}
|
|
254
303
|
if (settings.workflow || settings.branch) {
|
|
255
304
|
return {
|
|
@@ -257,6 +306,7 @@ const service = ({ strapi }) => ({
|
|
|
257
306
|
githubToken: settings.githubToken || "",
|
|
258
307
|
targets: [{
|
|
259
308
|
id: generateId(),
|
|
309
|
+
type: "github",
|
|
260
310
|
name: "Default",
|
|
261
311
|
workflow: settings.workflow || "deploy.yml",
|
|
262
312
|
branch: settings.branch || "master"
|
|
@@ -268,7 +318,11 @@ const service = ({ strapi }) => ({
|
|
|
268
318
|
async getSettings() {
|
|
269
319
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
270
320
|
let dbSettings = await store.get({ key: STORE_KEY });
|
|
321
|
+
const needsMigration = dbSettings && !Array.isArray(dbSettings.targets) && (dbSettings.workflow || dbSettings.branch);
|
|
271
322
|
dbSettings = this.migrateSettings(dbSettings);
|
|
323
|
+
if (needsMigration && dbSettings) {
|
|
324
|
+
await store.set({ key: STORE_KEY, value: dbSettings });
|
|
325
|
+
}
|
|
272
326
|
if (!dbSettings) {
|
|
273
327
|
return {
|
|
274
328
|
...DEFAULT_SETTINGS,
|
|
@@ -309,12 +363,18 @@ const service = ({ strapi }) => ({
|
|
|
309
363
|
const store = strapi.store({ type: "plugin", name: PLUGIN_ID });
|
|
310
364
|
let settings = await store.get({ key: STORE_KEY }) || DEFAULT_SETTINGS;
|
|
311
365
|
settings = this.migrateSettings(settings) || DEFAULT_SETTINGS;
|
|
366
|
+
const targetType = target.type || "github";
|
|
312
367
|
const newTarget = {
|
|
313
368
|
id: generateId(),
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
branch: target.branch || "master"
|
|
369
|
+
type: targetType,
|
|
370
|
+
name: target.name || "New Target"
|
|
317
371
|
};
|
|
372
|
+
if (targetType === "github") {
|
|
373
|
+
newTarget.workflow = target.workflow || "deploy.yml";
|
|
374
|
+
newTarget.branch = target.branch || "master";
|
|
375
|
+
} else if (targetType === "vercel") {
|
|
376
|
+
newTarget.webhookUrl = target.webhookUrl || "";
|
|
377
|
+
}
|
|
318
378
|
settings.targets = [...settings.targets || [], newTarget];
|
|
319
379
|
await store.set({ key: STORE_KEY, value: settings });
|
|
320
380
|
return newTarget;
|
|
@@ -326,12 +386,20 @@ const service = ({ strapi }) => ({
|
|
|
326
386
|
if (!settings?.targets) return null;
|
|
327
387
|
const targetIndex = settings.targets.findIndex((t) => t.id === targetId);
|
|
328
388
|
if (targetIndex === -1) return null;
|
|
329
|
-
settings.targets[targetIndex]
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
id: targetId
|
|
333
|
-
|
|
389
|
+
const existingTarget = settings.targets[targetIndex];
|
|
390
|
+
const targetType = updates.type || existingTarget.type || "github";
|
|
391
|
+
const updatedTarget = {
|
|
392
|
+
id: targetId,
|
|
393
|
+
type: targetType,
|
|
394
|
+
name: updates.name !== void 0 ? updates.name : existingTarget.name
|
|
334
395
|
};
|
|
396
|
+
if (targetType === "github") {
|
|
397
|
+
updatedTarget.workflow = updates.workflow !== void 0 ? updates.workflow : existingTarget.workflow;
|
|
398
|
+
updatedTarget.branch = updates.branch !== void 0 ? updates.branch : existingTarget.branch;
|
|
399
|
+
} else if (targetType === "vercel") {
|
|
400
|
+
updatedTarget.webhookUrl = updates.webhookUrl !== void 0 ? updates.webhookUrl : existingTarget.webhookUrl;
|
|
401
|
+
}
|
|
402
|
+
settings.targets[targetIndex] = updatedTarget;
|
|
335
403
|
await store.set({ key: STORE_KEY, value: settings });
|
|
336
404
|
return settings.targets[targetIndex];
|
|
337
405
|
},
|