@backstage/plugin-scaffolder-backend-module-gitlab 0.4.0 → 0.4.1-next.1
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/CHANGELOG.md +22 -0
- package/dist/index.cjs.js +1369 -1277
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +127 -109
- package/package.json +7 -7
package/dist/index.cjs.js
CHANGED
|
@@ -2,493 +2,161 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var errors = require('@backstage/errors');
|
|
5
6
|
var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
|
|
6
7
|
var node = require('@gitbeaker/node');
|
|
8
|
+
var yaml = require('yaml');
|
|
7
9
|
var zod = require('zod');
|
|
8
|
-
var errors = require('@backstage/errors');
|
|
9
10
|
var rest = require('@gitbeaker/rest');
|
|
10
|
-
var yaml = require('yaml');
|
|
11
|
-
var luxon = require('luxon');
|
|
12
11
|
var path = require('path');
|
|
13
12
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
14
|
-
var
|
|
13
|
+
var luxon = require('luxon');
|
|
15
14
|
var integration = require('@backstage/integration');
|
|
15
|
+
var alpha = require('@backstage/plugin-scaffolder-node/alpha');
|
|
16
16
|
|
|
17
17
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
18
18
|
|
|
19
19
|
var yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
|
|
20
20
|
var path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
repoUrl: zod.z.string({ description: "Repository Location" }),
|
|
24
|
-
token: zod.z.string({ description: "The token to use for authorization to GitLab" }).optional()
|
|
25
|
-
});
|
|
26
|
-
const commonGitlabConfigExample = {
|
|
27
|
-
repoUrl: "gitlab.com?owner=namespace-or-owner&repo=project-name",
|
|
28
|
-
token: "${{ secrets.USER_OAUTH_TOKEN }}"
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const parseRepoHost = (repoUrl) => {
|
|
32
|
-
let parsed;
|
|
33
|
-
try {
|
|
34
|
-
parsed = new URL(`https://${repoUrl}`);
|
|
35
|
-
} catch (error) {
|
|
36
|
-
throw new errors.InputError(
|
|
37
|
-
`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
return parsed.host;
|
|
41
|
-
};
|
|
42
|
-
const getToken = (config, integrations) => {
|
|
43
|
-
const host = parseRepoHost(config.repoUrl);
|
|
44
|
-
const integrationConfig = integrations.gitlab.byHost(host);
|
|
45
|
-
if (!integrationConfig) {
|
|
46
|
-
throw new errors.InputError(
|
|
47
|
-
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
const token = config.token || integrationConfig.config.token;
|
|
51
|
-
return { token, integrationConfig };
|
|
52
|
-
};
|
|
53
|
-
const parseRepoUrl = (repoUrl, integrations) => {
|
|
54
|
-
var _a, _b;
|
|
55
|
-
let parsed;
|
|
56
|
-
try {
|
|
57
|
-
parsed = new URL(`https://${repoUrl}`);
|
|
58
|
-
} catch (error) {
|
|
59
|
-
throw new errors.InputError(
|
|
60
|
-
`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
const host = parsed.host;
|
|
64
|
-
const owner = (_a = parsed.searchParams.get("owner")) != null ? _a : void 0;
|
|
65
|
-
const repo = parsed.searchParams.get("repo");
|
|
66
|
-
const type = (_b = integrations.byHost(host)) == null ? void 0 : _b.type;
|
|
67
|
-
if (!type) {
|
|
68
|
-
throw new errors.InputError(
|
|
69
|
-
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
return { host, owner, repo };
|
|
73
|
-
};
|
|
74
|
-
function getClient(props) {
|
|
75
|
-
const { host, token, integrations } = props;
|
|
76
|
-
const integrationConfig = integrations.gitlab.byHost(host);
|
|
77
|
-
if (!integrationConfig) {
|
|
78
|
-
throw new errors.InputError(
|
|
79
|
-
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
const { config } = integrationConfig;
|
|
83
|
-
if (!config.token && !token) {
|
|
84
|
-
throw new errors.InputError(`No token available for host ${host}`);
|
|
85
|
-
}
|
|
86
|
-
const requestToken = token || config.token;
|
|
87
|
-
const tokenType = token ? "oauthToken" : "token";
|
|
88
|
-
const gitlabOptions = {
|
|
89
|
-
host: config.baseUrl
|
|
90
|
-
};
|
|
91
|
-
gitlabOptions[tokenType] = requestToken;
|
|
92
|
-
return new rest.Gitlab(gitlabOptions);
|
|
93
|
-
}
|
|
94
|
-
function convertDate(inputDate, defaultDate) {
|
|
95
|
-
try {
|
|
96
|
-
return inputDate ? new Date(inputDate).toISOString() : new Date(defaultDate).toISOString();
|
|
97
|
-
} catch (error) {
|
|
98
|
-
throw new errors.InputError(`Error converting input date - ${error}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
async function getTopLevelParentGroup(client, groupId) {
|
|
102
|
-
try {
|
|
103
|
-
const topParentGroup = await client.Groups.show(groupId);
|
|
104
|
-
if (topParentGroup.parent_id) {
|
|
105
|
-
return getTopLevelParentGroup(
|
|
106
|
-
client,
|
|
107
|
-
topParentGroup.parent_id
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
return topParentGroup;
|
|
111
|
-
} catch (error) {
|
|
112
|
-
throw new errors.InputError(
|
|
113
|
-
`Error finding top-level parent group ID: ${error.message}`
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async function checkEpicScope(client, projectId, epicId) {
|
|
118
|
-
try {
|
|
119
|
-
const project = await client.Projects.show(projectId);
|
|
120
|
-
if (!project) {
|
|
121
|
-
throw new errors.InputError(
|
|
122
|
-
`Project with id ${projectId} not found. Check your GitLab instance.`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
const topParentGroup = await getTopLevelParentGroup(
|
|
126
|
-
client,
|
|
127
|
-
project.namespace.id
|
|
128
|
-
);
|
|
129
|
-
if (!topParentGroup) {
|
|
130
|
-
throw new errors.InputError(`Couldn't find a suitable top-level parent group.`);
|
|
131
|
-
}
|
|
132
|
-
const epic = (await client.Epics.all(topParentGroup.id)).find(
|
|
133
|
-
(x) => x.id === epicId
|
|
134
|
-
);
|
|
135
|
-
if (!epic) {
|
|
136
|
-
throw new errors.InputError(
|
|
137
|
-
`Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
const epicGroup = await client.Groups.show(epic.group_id);
|
|
141
|
-
const projectNamespace = project.path_with_namespace;
|
|
142
|
-
return projectNamespace.startsWith(epicGroup.full_path);
|
|
143
|
-
} catch (error) {
|
|
144
|
-
throw new errors.InputError(`Could not find epic scope: ${error.message}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const examples$7 = [
|
|
22
|
+
const examples$8 = [
|
|
149
23
|
{
|
|
150
|
-
description: "
|
|
24
|
+
description: "Initializes a git repository with the content in the workspace, and publishes it to GitLab with the default configuration.",
|
|
151
25
|
example: yaml__default.default.stringify({
|
|
152
26
|
steps: [
|
|
153
27
|
{
|
|
154
|
-
id: "
|
|
155
|
-
|
|
156
|
-
|
|
28
|
+
id: "publish",
|
|
29
|
+
action: "publish:gitlab",
|
|
30
|
+
name: "Publish to GitLab",
|
|
157
31
|
input: {
|
|
158
|
-
repoUrl: "gitlab.com"
|
|
159
|
-
path: ["group1"]
|
|
32
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name"
|
|
160
33
|
}
|
|
161
34
|
}
|
|
162
35
|
]
|
|
163
36
|
})
|
|
164
37
|
},
|
|
165
38
|
{
|
|
166
|
-
description: "
|
|
39
|
+
description: "Add a description.",
|
|
167
40
|
example: yaml__default.default.stringify({
|
|
168
41
|
steps: [
|
|
169
42
|
{
|
|
170
|
-
id: "
|
|
171
|
-
|
|
172
|
-
|
|
43
|
+
id: "publish",
|
|
44
|
+
action: "publish:gitlab",
|
|
45
|
+
name: "Publish to GitLab",
|
|
173
46
|
input: {
|
|
174
|
-
repoUrl: "gitlab.com",
|
|
175
|
-
|
|
47
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
48
|
+
description: "Initialize a git repository"
|
|
176
49
|
}
|
|
177
50
|
}
|
|
178
51
|
]
|
|
179
52
|
})
|
|
180
53
|
},
|
|
181
54
|
{
|
|
182
|
-
description: "
|
|
55
|
+
description: "Initializes a GitLab repository with an initial commit message, if not set defaults to `initial commit`.",
|
|
183
56
|
example: yaml__default.default.stringify({
|
|
184
57
|
steps: [
|
|
185
58
|
{
|
|
186
|
-
id: "
|
|
187
|
-
|
|
188
|
-
|
|
59
|
+
id: "publish",
|
|
60
|
+
action: "publish:gitlab",
|
|
61
|
+
name: "Publish to GitLab",
|
|
189
62
|
input: {
|
|
190
|
-
repoUrl: "gitlab.com",
|
|
191
|
-
|
|
63
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
64
|
+
description: "Initialize a git repository",
|
|
65
|
+
gitCommitMessage: "Started a project."
|
|
192
66
|
}
|
|
193
67
|
}
|
|
194
68
|
]
|
|
195
69
|
})
|
|
196
70
|
},
|
|
197
71
|
{
|
|
198
|
-
description: "
|
|
72
|
+
description: "Initializes a GitLab repository with aditional settings.",
|
|
199
73
|
example: yaml__default.default.stringify({
|
|
200
74
|
steps: [
|
|
201
75
|
{
|
|
202
|
-
id: "
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
isDryRun: true,
|
|
76
|
+
id: "publish",
|
|
77
|
+
action: "publish:gitlab",
|
|
78
|
+
name: "Publish to GitLab",
|
|
206
79
|
input: {
|
|
207
|
-
repoUrl: "
|
|
208
|
-
|
|
80
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
81
|
+
settings: {
|
|
82
|
+
ci_config_path: ".gitlab-ci.yml",
|
|
83
|
+
visibility: "public"
|
|
84
|
+
}
|
|
209
85
|
}
|
|
210
86
|
}
|
|
211
87
|
]
|
|
212
88
|
})
|
|
213
|
-
}
|
|
214
|
-
];
|
|
215
|
-
|
|
216
|
-
const createGitlabGroupEnsureExistsAction = (options) => {
|
|
217
|
-
const { integrations } = options;
|
|
218
|
-
return pluginScaffolderNode.createTemplateAction({
|
|
219
|
-
id: "gitlab:group:ensureExists",
|
|
220
|
-
description: "Ensures a Gitlab group exists",
|
|
221
|
-
supportsDryRun: true,
|
|
222
|
-
examples: examples$7,
|
|
223
|
-
schema: {
|
|
224
|
-
input: commonGitlabConfig.merge(
|
|
225
|
-
zod.z.object({
|
|
226
|
-
path: zod.z.array(zod.z.string(), {
|
|
227
|
-
description: "A path of group names that is ensured to exist"
|
|
228
|
-
}).min(1)
|
|
229
|
-
})
|
|
230
|
-
),
|
|
231
|
-
output: zod.z.object({
|
|
232
|
-
groupId: zod.z.number({ description: "The id of the innermost sub-group" }).optional()
|
|
233
|
-
})
|
|
234
|
-
},
|
|
235
|
-
async handler(ctx) {
|
|
236
|
-
if (ctx.isDryRun) {
|
|
237
|
-
ctx.output("groupId", 42);
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const { path } = ctx.input;
|
|
241
|
-
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
242
|
-
const api = new node.Gitlab({
|
|
243
|
-
host: integrationConfig.config.baseUrl,
|
|
244
|
-
token
|
|
245
|
-
});
|
|
246
|
-
let currentPath = null;
|
|
247
|
-
let parent = null;
|
|
248
|
-
for (const pathElement of path) {
|
|
249
|
-
const fullPath = currentPath ? `${currentPath}/${pathElement}` : pathElement;
|
|
250
|
-
const result = await api.Groups.search(
|
|
251
|
-
fullPath
|
|
252
|
-
);
|
|
253
|
-
const subGroup = result.find(
|
|
254
|
-
(searchPathElem) => searchPathElem.full_path === fullPath
|
|
255
|
-
);
|
|
256
|
-
if (!subGroup) {
|
|
257
|
-
ctx.logger.info(`creating missing group ${fullPath}`);
|
|
258
|
-
parent = await api.Groups.create(
|
|
259
|
-
pathElement,
|
|
260
|
-
pathElement,
|
|
261
|
-
parent ? {
|
|
262
|
-
parent_id: parent.id
|
|
263
|
-
} : {}
|
|
264
|
-
);
|
|
265
|
-
} else {
|
|
266
|
-
parent = subGroup;
|
|
267
|
-
}
|
|
268
|
-
currentPath = fullPath;
|
|
269
|
-
}
|
|
270
|
-
if (parent !== null) {
|
|
271
|
-
ctx.output("groupId", parent == null ? void 0 : parent.id);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
const examples$6 = [
|
|
89
|
+
},
|
|
278
90
|
{
|
|
279
|
-
description: "
|
|
91
|
+
description: "Initializes a GitLab repository with fast forward merge and always squash settings.",
|
|
280
92
|
example: yaml__default.default.stringify({
|
|
281
93
|
steps: [
|
|
282
94
|
{
|
|
283
|
-
id: "
|
|
284
|
-
action: "gitlab
|
|
285
|
-
name: "
|
|
286
|
-
input: {
|
|
287
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
288
|
-
projectId: "456",
|
|
289
|
-
name: "tokenname"
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
]
|
|
293
|
-
})
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
description: "Create a GitLab project deploy token with custom scopes.",
|
|
297
|
-
example: yaml__default.default.stringify({
|
|
298
|
-
steps: [
|
|
299
|
-
{
|
|
300
|
-
id: "createDeployToken",
|
|
301
|
-
action: "gitlab:projectDeployToken:create",
|
|
302
|
-
name: "Create GitLab Project Deploy Token",
|
|
303
|
-
input: {
|
|
304
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
305
|
-
projectId: "789",
|
|
306
|
-
name: "tokenname",
|
|
307
|
-
scopes: ["read_registry", "write_repository"]
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
]
|
|
311
|
-
})
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
description: "Create a GitLab project deploy token with a specified name.",
|
|
315
|
-
example: yaml__default.default.stringify({
|
|
316
|
-
steps: [
|
|
317
|
-
{
|
|
318
|
-
id: "createDeployToken",
|
|
319
|
-
action: "gitlab:projectDeployToken:create",
|
|
320
|
-
name: "Create GitLab Project Deploy Token",
|
|
321
|
-
input: {
|
|
322
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
323
|
-
projectId: "101112",
|
|
324
|
-
name: "my-custom-token"
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
]
|
|
328
|
-
})
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
description: "Create a GitLab project deploy token with a numeric project ID.",
|
|
332
|
-
example: yaml__default.default.stringify({
|
|
333
|
-
steps: [
|
|
334
|
-
{
|
|
335
|
-
id: "createDeployToken",
|
|
336
|
-
action: "gitlab:projectDeployToken:create",
|
|
337
|
-
name: "Create GitLab Project Deploy Token",
|
|
338
|
-
input: {
|
|
339
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
340
|
-
projectId: 42,
|
|
341
|
-
name: "tokenname"
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
]
|
|
345
|
-
})
|
|
346
|
-
},
|
|
347
|
-
{
|
|
348
|
-
description: "Create a GitLab project deploy token with a custom username",
|
|
349
|
-
example: yaml__default.default.stringify({
|
|
350
|
-
steps: [
|
|
351
|
-
{
|
|
352
|
-
id: "createDeployToken",
|
|
353
|
-
action: "gitlab:projectDeployToken:create",
|
|
354
|
-
name: "Create GitLab Project Deploy Token",
|
|
355
|
-
input: {
|
|
356
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
357
|
-
projectId: 42,
|
|
358
|
-
name: "tokenname",
|
|
359
|
-
username: "tokenuser"
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
]
|
|
363
|
-
})
|
|
364
|
-
}
|
|
365
|
-
];
|
|
366
|
-
|
|
367
|
-
const createGitlabProjectDeployTokenAction = (options) => {
|
|
368
|
-
const { integrations } = options;
|
|
369
|
-
return pluginScaffolderNode.createTemplateAction({
|
|
370
|
-
id: "gitlab:projectDeployToken:create",
|
|
371
|
-
examples: examples$6,
|
|
372
|
-
schema: {
|
|
373
|
-
input: commonGitlabConfig.merge(
|
|
374
|
-
zod.z.object({
|
|
375
|
-
projectId: zod.z.union([zod.z.number(), zod.z.string()], {
|
|
376
|
-
description: "Project ID"
|
|
377
|
-
}),
|
|
378
|
-
name: zod.z.string({ description: "Deploy Token Name" }),
|
|
379
|
-
username: zod.z.string({ description: "Deploy Token Username" }).optional(),
|
|
380
|
-
scopes: zod.z.array(zod.z.string(), { description: "Scopes" }).optional()
|
|
381
|
-
})
|
|
382
|
-
),
|
|
383
|
-
output: zod.z.object({
|
|
384
|
-
deploy_token: zod.z.string({ description: "Deploy Token" }),
|
|
385
|
-
user: zod.z.string({ description: "User" })
|
|
386
|
-
})
|
|
387
|
-
},
|
|
388
|
-
async handler(ctx) {
|
|
389
|
-
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
|
390
|
-
const { projectId, name, username, scopes } = ctx.input;
|
|
391
|
-
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
392
|
-
const api = new node.Gitlab({
|
|
393
|
-
host: integrationConfig.config.baseUrl,
|
|
394
|
-
token
|
|
395
|
-
});
|
|
396
|
-
const deployToken = await api.ProjectDeployTokens.add(
|
|
397
|
-
projectId,
|
|
398
|
-
name,
|
|
399
|
-
scopes,
|
|
400
|
-
{
|
|
401
|
-
username
|
|
402
|
-
}
|
|
403
|
-
);
|
|
404
|
-
if (!deployToken.hasOwnProperty("token")) {
|
|
405
|
-
throw new errors.InputError(`No deploy_token given from gitlab instance`);
|
|
406
|
-
}
|
|
407
|
-
ctx.output("deploy_token", deployToken.token);
|
|
408
|
-
ctx.output("user", deployToken.username);
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const examples$5 = [
|
|
414
|
-
{
|
|
415
|
-
description: "Create a GitLab project access token with minimal options.",
|
|
416
|
-
example: yaml__default.default.stringify({
|
|
417
|
-
steps: [
|
|
418
|
-
{
|
|
419
|
-
id: "createAccessToken",
|
|
420
|
-
action: "gitlab:projectAccessToken:create",
|
|
421
|
-
name: "Create GitLab Project Access Token",
|
|
422
|
-
input: {
|
|
423
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
424
|
-
projectId: "456"
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
]
|
|
428
|
-
})
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
description: "Create a GitLab project access token with custom scopes.",
|
|
432
|
-
example: yaml__default.default.stringify({
|
|
433
|
-
steps: [
|
|
434
|
-
{
|
|
435
|
-
id: "createAccessToken",
|
|
436
|
-
action: "gitlab:projectAccessToken:create",
|
|
437
|
-
name: "Create GitLab Project Access Token",
|
|
438
|
-
input: {
|
|
439
|
-
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
440
|
-
projectId: "789",
|
|
441
|
-
scopes: ["read_registry", "write_repository"]
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
]
|
|
445
|
-
})
|
|
446
|
-
},
|
|
447
|
-
{
|
|
448
|
-
description: "Create a GitLab project access token with a specified name.",
|
|
449
|
-
example: yaml__default.default.stringify({
|
|
450
|
-
steps: [
|
|
451
|
-
{
|
|
452
|
-
id: "createAccessToken",
|
|
453
|
-
action: "gitlab:projectAccessToken:create",
|
|
454
|
-
name: "Create GitLab Project Access Token",
|
|
95
|
+
id: "publish",
|
|
96
|
+
action: "publish:gitlab",
|
|
97
|
+
name: "Publish to GitLab",
|
|
455
98
|
input: {
|
|
456
|
-
repoUrl: "gitlab.com?repo=
|
|
457
|
-
|
|
458
|
-
|
|
99
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
100
|
+
settings: {
|
|
101
|
+
merge_method: "ff",
|
|
102
|
+
squash_option: "always"
|
|
103
|
+
}
|
|
459
104
|
}
|
|
460
105
|
}
|
|
461
106
|
]
|
|
462
107
|
})
|
|
463
108
|
},
|
|
464
109
|
{
|
|
465
|
-
description: "
|
|
110
|
+
description: "Initializes a GitLab repository with branch settings.",
|
|
466
111
|
example: yaml__default.default.stringify({
|
|
467
112
|
steps: [
|
|
468
113
|
{
|
|
469
|
-
id: "
|
|
470
|
-
action: "gitlab
|
|
471
|
-
name: "
|
|
114
|
+
id: "publish",
|
|
115
|
+
action: "publish:gitlab",
|
|
116
|
+
name: "Publish to GitLab",
|
|
472
117
|
input: {
|
|
473
|
-
repoUrl: "gitlab.com?repo=
|
|
474
|
-
|
|
118
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
119
|
+
branches: [
|
|
120
|
+
{
|
|
121
|
+
name: "dev",
|
|
122
|
+
create: true,
|
|
123
|
+
protected: true,
|
|
124
|
+
ref: "master"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "master",
|
|
128
|
+
protected: true
|
|
129
|
+
}
|
|
130
|
+
]
|
|
475
131
|
}
|
|
476
132
|
}
|
|
477
133
|
]
|
|
478
134
|
})
|
|
479
135
|
},
|
|
480
136
|
{
|
|
481
|
-
description: "
|
|
137
|
+
description: "Initializes a GitLab repository with environment variables.",
|
|
482
138
|
example: yaml__default.default.stringify({
|
|
483
139
|
steps: [
|
|
484
140
|
{
|
|
485
|
-
id: "
|
|
486
|
-
action: "gitlab
|
|
487
|
-
name: "
|
|
141
|
+
id: "publish",
|
|
142
|
+
action: "publish:gitlab",
|
|
143
|
+
name: "Publish to GitLab",
|
|
488
144
|
input: {
|
|
489
|
-
repoUrl: "gitlab.com?repo=
|
|
490
|
-
|
|
491
|
-
|
|
145
|
+
repoUrl: "gitlab.com?repo=project_name&owner=group_name",
|
|
146
|
+
projectVariables: [
|
|
147
|
+
{
|
|
148
|
+
key: "key1",
|
|
149
|
+
value: "value1",
|
|
150
|
+
protected: true,
|
|
151
|
+
masked: false
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
key: "key2",
|
|
155
|
+
value: "value2",
|
|
156
|
+
protected: true,
|
|
157
|
+
masked: false
|
|
158
|
+
}
|
|
159
|
+
]
|
|
492
160
|
}
|
|
493
161
|
}
|
|
494
162
|
]
|
|
@@ -496,213 +164,557 @@ const examples$5 = [
|
|
|
496
164
|
}
|
|
497
165
|
];
|
|
498
166
|
|
|
499
|
-
|
|
500
|
-
const { integrations } = options;
|
|
167
|
+
function createPublishGitlabAction(options) {
|
|
168
|
+
const { integrations, config } = options;
|
|
501
169
|
return pluginScaffolderNode.createTemplateAction({
|
|
502
|
-
id: "gitlab
|
|
503
|
-
|
|
170
|
+
id: "publish:gitlab",
|
|
171
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to GitLab.",
|
|
172
|
+
examples: examples$8,
|
|
504
173
|
schema: {
|
|
505
|
-
input:
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
174
|
+
input: {
|
|
175
|
+
type: "object",
|
|
176
|
+
required: ["repoUrl"],
|
|
177
|
+
properties: {
|
|
178
|
+
repoUrl: {
|
|
179
|
+
title: "Repository Location",
|
|
180
|
+
type: "string",
|
|
181
|
+
description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`
|
|
182
|
+
},
|
|
183
|
+
repoVisibility: {
|
|
184
|
+
title: "Repository Visibility",
|
|
185
|
+
description: `Sets the visibility of the repository. The default value is 'private'. (deprecated, use settings.visibility instead)`,
|
|
186
|
+
type: "string",
|
|
187
|
+
enum: ["private", "public", "internal"]
|
|
188
|
+
},
|
|
189
|
+
defaultBranch: {
|
|
190
|
+
title: "Default Branch",
|
|
191
|
+
type: "string",
|
|
192
|
+
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
193
|
+
},
|
|
194
|
+
gitCommitMessage: {
|
|
195
|
+
title: "Git Commit Message",
|
|
196
|
+
type: "string",
|
|
197
|
+
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
198
|
+
},
|
|
199
|
+
gitAuthorName: {
|
|
200
|
+
title: "Default Author Name",
|
|
201
|
+
type: "string",
|
|
202
|
+
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
203
|
+
},
|
|
204
|
+
gitAuthorEmail: {
|
|
205
|
+
title: "Default Author Email",
|
|
206
|
+
type: "string",
|
|
207
|
+
description: `Sets the default author email for the commit.`
|
|
208
|
+
},
|
|
209
|
+
sourcePath: {
|
|
210
|
+
title: "Source Path",
|
|
211
|
+
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
212
|
+
type: "string"
|
|
213
|
+
},
|
|
214
|
+
token: {
|
|
215
|
+
title: "Authentication Token",
|
|
216
|
+
type: "string",
|
|
217
|
+
description: "The token to use for authorization to GitLab"
|
|
218
|
+
},
|
|
219
|
+
setUserAsOwner: {
|
|
220
|
+
title: "Set User As Owner",
|
|
221
|
+
type: "boolean",
|
|
222
|
+
description: "Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host"
|
|
223
|
+
},
|
|
224
|
+
topics: {
|
|
225
|
+
title: "Topic labels",
|
|
226
|
+
description: "Topic labels to apply on the repository. (deprecated, use settings.topics instead)",
|
|
227
|
+
type: "array",
|
|
228
|
+
items: {
|
|
229
|
+
type: "string"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
settings: {
|
|
233
|
+
title: "Project settings",
|
|
234
|
+
description: "Additional project settings, based on https://docs.gitlab.com/ee/api/projects.html#create-project attributes",
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: {
|
|
237
|
+
path: {
|
|
238
|
+
title: "Project path",
|
|
239
|
+
description: "Repository name for new project. Generated based on name if not provided (generated as lowercase with dashes).",
|
|
240
|
+
type: "string"
|
|
241
|
+
},
|
|
242
|
+
auto_devops_enabled: {
|
|
243
|
+
title: "Auto DevOps enabled",
|
|
244
|
+
description: "Enable Auto DevOps for this project",
|
|
245
|
+
type: "boolean"
|
|
246
|
+
},
|
|
247
|
+
ci_config_path: {
|
|
248
|
+
title: "CI config path",
|
|
249
|
+
description: "Custom CI config path for this project",
|
|
250
|
+
type: "string"
|
|
251
|
+
},
|
|
252
|
+
description: {
|
|
253
|
+
title: "Project description",
|
|
254
|
+
description: "Short project description",
|
|
255
|
+
type: "string"
|
|
256
|
+
},
|
|
257
|
+
merge_method: {
|
|
258
|
+
title: "Merge Method to use",
|
|
259
|
+
description: "Merge Methods (merge, rebase_merge, ff)",
|
|
260
|
+
type: "string",
|
|
261
|
+
enum: ["merge", "rebase_merge", "ff"]
|
|
262
|
+
},
|
|
263
|
+
squash_option: {
|
|
264
|
+
title: "Squash option",
|
|
265
|
+
description: "Set squash option for the project (never, always, default_on, default_off)",
|
|
266
|
+
type: "string",
|
|
267
|
+
enum: ["default_off", "default_on", "never", "always"]
|
|
268
|
+
},
|
|
269
|
+
topics: {
|
|
270
|
+
title: "Topic labels",
|
|
271
|
+
description: "Topic labels to apply on the repository",
|
|
272
|
+
type: "array",
|
|
273
|
+
items: {
|
|
274
|
+
type: "string"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
visibility: {
|
|
278
|
+
title: "Project visibility",
|
|
279
|
+
description: "The visibility of the project. Can be private, internal, or public. The default value is private.",
|
|
280
|
+
type: "string",
|
|
281
|
+
enum: ["private", "public", "internal"]
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
branches: {
|
|
286
|
+
title: "Project branches settings",
|
|
287
|
+
type: "array",
|
|
288
|
+
items: {
|
|
289
|
+
type: "object",
|
|
290
|
+
required: ["name"],
|
|
291
|
+
properties: {
|
|
292
|
+
name: {
|
|
293
|
+
title: "Branch name",
|
|
294
|
+
type: "string"
|
|
295
|
+
},
|
|
296
|
+
protect: {
|
|
297
|
+
title: "Should branch be protected",
|
|
298
|
+
description: `Will mark branch as protected. The default value is 'false'`,
|
|
299
|
+
type: "boolean"
|
|
300
|
+
},
|
|
301
|
+
create: {
|
|
302
|
+
title: "Should branch be created",
|
|
303
|
+
description: `If branch does not exist, it will be created from provided ref. The default value is 'false'`,
|
|
304
|
+
type: "boolean"
|
|
305
|
+
},
|
|
306
|
+
ref: {
|
|
307
|
+
title: "Branch reference",
|
|
308
|
+
description: `Branch reference to create branch from. The default value is 'master'`,
|
|
309
|
+
type: "string"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
projectVariables: {
|
|
315
|
+
title: "Project variables",
|
|
316
|
+
description: "Project variables settings based on Gitlab Project Environments API - https://docs.gitlab.com/ee/api/project_level_variables.html#create-a-variable",
|
|
317
|
+
type: "array",
|
|
318
|
+
items: {
|
|
319
|
+
type: "object",
|
|
320
|
+
required: ["key", "value"],
|
|
321
|
+
properties: {
|
|
322
|
+
key: {
|
|
323
|
+
title: "Variable key",
|
|
324
|
+
description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed",
|
|
325
|
+
type: "string"
|
|
326
|
+
},
|
|
327
|
+
value: {
|
|
328
|
+
title: "Variable value",
|
|
329
|
+
description: "The value of a variable",
|
|
330
|
+
type: "string"
|
|
331
|
+
},
|
|
332
|
+
description: {
|
|
333
|
+
title: "Variable description",
|
|
334
|
+
description: `The description of the variable. The default value is 'null'`,
|
|
335
|
+
type: "string"
|
|
336
|
+
},
|
|
337
|
+
variable_type: {
|
|
338
|
+
title: "Variable type",
|
|
339
|
+
description: `The type of a variable. The default value is 'env_var'`,
|
|
340
|
+
type: "string",
|
|
341
|
+
enum: ["env_var", "file"]
|
|
342
|
+
},
|
|
343
|
+
protected: {
|
|
344
|
+
title: "Variable protection",
|
|
345
|
+
description: `Whether the variable is protected. The default value is 'false'`,
|
|
346
|
+
type: "boolean"
|
|
347
|
+
},
|
|
348
|
+
raw: {
|
|
349
|
+
title: "Variable raw",
|
|
350
|
+
description: `Whether the variable is in raw format. The default value is 'false'`,
|
|
351
|
+
type: "boolean"
|
|
352
|
+
},
|
|
353
|
+
environment_scope: {
|
|
354
|
+
title: "Variable environment scope",
|
|
355
|
+
description: `The environment_scope of the variable. The default value is '*'`,
|
|
356
|
+
type: "string"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
output: {
|
|
364
|
+
type: "object",
|
|
365
|
+
properties: {
|
|
366
|
+
remoteUrl: {
|
|
367
|
+
title: "A URL to the repository with the provider",
|
|
368
|
+
type: "string"
|
|
369
|
+
},
|
|
370
|
+
repoContentsUrl: {
|
|
371
|
+
title: "A URL to the root of the repository",
|
|
372
|
+
type: "string"
|
|
373
|
+
},
|
|
374
|
+
projectId: {
|
|
375
|
+
title: "The ID of the project",
|
|
376
|
+
type: "string"
|
|
377
|
+
},
|
|
378
|
+
commitHash: {
|
|
379
|
+
title: "The git commit hash of the initial commit",
|
|
380
|
+
type: "string"
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
527
384
|
},
|
|
528
385
|
async handler(ctx) {
|
|
529
|
-
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
|
530
386
|
const {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
387
|
+
repoUrl,
|
|
388
|
+
repoVisibility = "private",
|
|
389
|
+
defaultBranch = "master",
|
|
390
|
+
gitCommitMessage = "initial commit",
|
|
391
|
+
gitAuthorName,
|
|
392
|
+
gitAuthorEmail,
|
|
393
|
+
setUserAsOwner = false,
|
|
394
|
+
topics = [],
|
|
395
|
+
settings = {},
|
|
396
|
+
branches = [],
|
|
397
|
+
projectVariables = []
|
|
536
398
|
} = ctx.input;
|
|
537
|
-
const {
|
|
538
|
-
if (!
|
|
399
|
+
const { owner, repo, host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
|
|
400
|
+
if (!owner) {
|
|
539
401
|
throw new errors.InputError(
|
|
540
|
-
`No
|
|
402
|
+
`No owner provided for host: ${host}, and repo ${repo}`
|
|
541
403
|
);
|
|
542
404
|
}
|
|
543
|
-
|
|
544
|
-
if (!
|
|
545
|
-
|
|
546
|
-
host
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
405
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
406
|
+
if (!integrationConfig) {
|
|
407
|
+
throw new errors.InputError(
|
|
408
|
+
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
if (!integrationConfig.config.token && !ctx.input.token) {
|
|
412
|
+
throw new errors.InputError(`No token available for host ${host}`);
|
|
413
|
+
}
|
|
414
|
+
const token = ctx.input.token || integrationConfig.config.token;
|
|
415
|
+
const tokenType = ctx.input.token ? "oauthToken" : "token";
|
|
416
|
+
const client = new node.Gitlab({
|
|
417
|
+
host: integrationConfig.config.baseUrl,
|
|
418
|
+
[tokenType]: token
|
|
419
|
+
});
|
|
420
|
+
let targetNamespaceId;
|
|
421
|
+
try {
|
|
422
|
+
const namespaceResponse = await client.Namespaces.show(owner);
|
|
423
|
+
targetNamespaceId = namespaceResponse.id;
|
|
424
|
+
} catch (e) {
|
|
425
|
+
if (e.response && e.response.statusCode === 404) {
|
|
426
|
+
throw new errors.InputError(
|
|
427
|
+
`The namespace ${owner} is not found or the user doesn't have permissions to access it`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
throw e;
|
|
431
|
+
}
|
|
432
|
+
const { id: userId } = await client.Users.current();
|
|
433
|
+
if (!targetNamespaceId) {
|
|
434
|
+
targetNamespaceId = userId;
|
|
435
|
+
}
|
|
436
|
+
const { id: projectId, http_url_to_repo } = await client.Projects.create({
|
|
437
|
+
namespace_id: targetNamespaceId,
|
|
438
|
+
name: repo,
|
|
439
|
+
visibility: repoVisibility,
|
|
440
|
+
...topics.length ? { topics } : {},
|
|
441
|
+
...Object.keys(settings).length ? { ...settings } : {}
|
|
442
|
+
});
|
|
443
|
+
if (setUserAsOwner && integrationConfig.config.token) {
|
|
444
|
+
const adminClient = new node.Gitlab({
|
|
551
445
|
host: integrationConfig.config.baseUrl,
|
|
552
|
-
|
|
446
|
+
token: integrationConfig.config.token
|
|
553
447
|
});
|
|
448
|
+
await adminClient.ProjectMembers.add(projectId, userId, 50);
|
|
554
449
|
}
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
450
|
+
const remoteUrl = http_url_to_repo.replace(/\.git$/, "");
|
|
451
|
+
const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`;
|
|
452
|
+
const gitAuthorInfo = {
|
|
453
|
+
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
454
|
+
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
455
|
+
};
|
|
456
|
+
const commitResult = await pluginScaffolderNode.initRepoAndPush({
|
|
457
|
+
dir: pluginScaffolderNode.getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
458
|
+
remoteUrl: http_url_to_repo,
|
|
459
|
+
defaultBranch,
|
|
460
|
+
auth: {
|
|
461
|
+
username: "oauth2",
|
|
462
|
+
password: token
|
|
463
|
+
},
|
|
464
|
+
logger: ctx.logger,
|
|
465
|
+
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
466
|
+
gitAuthorInfo
|
|
467
|
+
});
|
|
468
|
+
if (branches) {
|
|
469
|
+
for (const branch of branches) {
|
|
470
|
+
const {
|
|
471
|
+
name,
|
|
472
|
+
protect = false,
|
|
473
|
+
create = false,
|
|
474
|
+
ref = "master"
|
|
475
|
+
} = branch;
|
|
476
|
+
if (create) {
|
|
477
|
+
try {
|
|
478
|
+
await client.Branches.create(projectId, name, ref);
|
|
479
|
+
} catch (e) {
|
|
480
|
+
throw new errors.InputError(
|
|
481
|
+
`Branch creation failed for ${name}. ${printGitlabError(e)}`
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
ctx.logger.info(
|
|
485
|
+
`Branch ${name} created for ${projectId} with ref ${ref}`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (protect) {
|
|
489
|
+
try {
|
|
490
|
+
await client.ProtectedBranches.protect(projectId, name);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
throw new errors.InputError(
|
|
493
|
+
`Branch protection failed for ${name}. ${printGitlabError(e)}`
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
ctx.logger.info(`Branch ${name} protected for ${projectId}`);
|
|
497
|
+
}
|
|
562
498
|
}
|
|
563
|
-
);
|
|
564
|
-
if (!response.token) {
|
|
565
|
-
throw new Error("Could not create project access token");
|
|
566
499
|
}
|
|
567
|
-
|
|
500
|
+
if (projectVariables) {
|
|
501
|
+
for (const variable of projectVariables) {
|
|
502
|
+
const variableWithDefaults = Object.assign(variable, {
|
|
503
|
+
variable_type: variable.variable_type ?? "env_var",
|
|
504
|
+
protected: variable.protected ?? false,
|
|
505
|
+
masked: variable.masked ?? false,
|
|
506
|
+
raw: variable.raw ?? false,
|
|
507
|
+
environment_scope: variable.environment_scope ?? "*"
|
|
508
|
+
});
|
|
509
|
+
try {
|
|
510
|
+
await client.ProjectVariables.create(
|
|
511
|
+
projectId,
|
|
512
|
+
variableWithDefaults
|
|
513
|
+
);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
throw new errors.InputError(
|
|
516
|
+
`Environment variable creation failed for ${variableWithDefaults.key}. ${printGitlabError(e)}`
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
ctx.output("commitHash", commitResult?.commitHash);
|
|
522
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
523
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
524
|
+
ctx.output("projectId", projectId);
|
|
568
525
|
}
|
|
569
526
|
});
|
|
527
|
+
}
|
|
528
|
+
function printGitlabError(error) {
|
|
529
|
+
return JSON.stringify({ code: error.code, message: error.description });
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const commonGitlabConfig = zod.z.object({
|
|
533
|
+
repoUrl: zod.z.string({ description: "Repository Location" }),
|
|
534
|
+
token: zod.z.string({ description: "The token to use for authorization to GitLab" }).optional()
|
|
535
|
+
});
|
|
536
|
+
const commonGitlabConfigExample = {
|
|
537
|
+
repoUrl: "gitlab.com?owner=namespace-or-owner&repo=project-name",
|
|
538
|
+
token: "${{ secrets.USER_OAUTH_TOKEN }}"
|
|
570
539
|
};
|
|
571
540
|
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
{
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
}
|
|
541
|
+
const parseRepoHost = (repoUrl) => {
|
|
542
|
+
let parsed;
|
|
543
|
+
try {
|
|
544
|
+
parsed = new URL(`https://${repoUrl}`);
|
|
545
|
+
} catch (error) {
|
|
546
|
+
throw new errors.InputError(
|
|
547
|
+
`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
return parsed.host;
|
|
551
|
+
};
|
|
552
|
+
const getToken = (config, integrations) => {
|
|
553
|
+
const host = parseRepoHost(config.repoUrl);
|
|
554
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
555
|
+
if (!integrationConfig) {
|
|
556
|
+
throw new errors.InputError(
|
|
557
|
+
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
const token = config.token || integrationConfig.config.token;
|
|
561
|
+
return { token, integrationConfig };
|
|
562
|
+
};
|
|
563
|
+
const parseRepoUrl = (repoUrl, integrations) => {
|
|
564
|
+
let parsed;
|
|
565
|
+
try {
|
|
566
|
+
parsed = new URL(`https://${repoUrl}`);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
throw new errors.InputError(
|
|
569
|
+
`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
const host = parsed.host;
|
|
573
|
+
const owner = parsed.searchParams.get("owner") ?? void 0;
|
|
574
|
+
const repo = parsed.searchParams.get("repo");
|
|
575
|
+
const type = integrations.byHost(host)?.type;
|
|
576
|
+
if (!type) {
|
|
577
|
+
throw new errors.InputError(
|
|
578
|
+
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
return { host, owner, repo };
|
|
582
|
+
};
|
|
583
|
+
function getClient(props) {
|
|
584
|
+
const { host, token, integrations } = props;
|
|
585
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
586
|
+
if (!integrationConfig) {
|
|
587
|
+
throw new errors.InputError(
|
|
588
|
+
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
const { config } = integrationConfig;
|
|
592
|
+
if (!config.token && !token) {
|
|
593
|
+
throw new errors.InputError(`No token available for host ${host}`);
|
|
594
|
+
}
|
|
595
|
+
const requestToken = token || config.token;
|
|
596
|
+
const tokenType = token ? "oauthToken" : "token";
|
|
597
|
+
const gitlabOptions = {
|
|
598
|
+
host: config.baseUrl
|
|
599
|
+
};
|
|
600
|
+
gitlabOptions[tokenType] = requestToken;
|
|
601
|
+
return new rest.Gitlab(gitlabOptions);
|
|
602
|
+
}
|
|
603
|
+
function convertDate(inputDate, defaultDate) {
|
|
604
|
+
try {
|
|
605
|
+
return inputDate ? new Date(inputDate).toISOString() : new Date(defaultDate).toISOString();
|
|
606
|
+
} catch (error) {
|
|
607
|
+
throw new errors.InputError(`Error converting input date - ${error}`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
async function getTopLevelParentGroup(client, groupId) {
|
|
611
|
+
try {
|
|
612
|
+
const topParentGroup = await client.Groups.show(groupId);
|
|
613
|
+
if (topParentGroup.parent_id) {
|
|
614
|
+
return getTopLevelParentGroup(
|
|
615
|
+
client,
|
|
616
|
+
topParentGroup.parent_id
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return topParentGroup;
|
|
620
|
+
} catch (error) {
|
|
621
|
+
throw new errors.InputError(
|
|
622
|
+
`Error finding top-level parent group ID: ${error.message}`
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
async function checkEpicScope(client, projectId, epicId) {
|
|
627
|
+
try {
|
|
628
|
+
const project = await client.Projects.show(projectId);
|
|
629
|
+
if (!project) {
|
|
630
|
+
throw new errors.InputError(
|
|
631
|
+
`Project with id ${projectId} not found. Check your GitLab instance.`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
const topParentGroup = await getTopLevelParentGroup(
|
|
635
|
+
client,
|
|
636
|
+
project.namespace.id
|
|
637
|
+
);
|
|
638
|
+
if (!topParentGroup) {
|
|
639
|
+
throw new errors.InputError(`Couldn't find a suitable top-level parent group.`);
|
|
640
|
+
}
|
|
641
|
+
const epic = (await client.Epics.all(topParentGroup.id)).find(
|
|
642
|
+
(x) => x.id === epicId
|
|
643
|
+
);
|
|
644
|
+
if (!epic) {
|
|
645
|
+
throw new errors.InputError(
|
|
646
|
+
`Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
const epicGroup = await client.Groups.show(epic.group_id);
|
|
650
|
+
const projectNamespace = project.path_with_namespace;
|
|
651
|
+
return projectNamespace.startsWith(epicGroup.full_path);
|
|
652
|
+
} catch (error) {
|
|
653
|
+
throw new errors.InputError(`Could not find epic scope: ${error.message}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const examples$7 = [
|
|
631
658
|
{
|
|
632
|
-
description: "
|
|
659
|
+
description: "Creating a group at the top level",
|
|
633
660
|
example: yaml__default.default.stringify({
|
|
634
661
|
steps: [
|
|
635
662
|
{
|
|
636
|
-
id: "
|
|
637
|
-
|
|
638
|
-
|
|
663
|
+
id: "gitlabGroup",
|
|
664
|
+
name: "Group",
|
|
665
|
+
action: "gitlab:group:ensureExists",
|
|
639
666
|
input: {
|
|
640
|
-
repoUrl: "gitlab.com
|
|
641
|
-
|
|
642
|
-
key: "DB_PASSWORD",
|
|
643
|
-
value: "password123",
|
|
644
|
-
variableType: "env_var",
|
|
645
|
-
masked: true
|
|
667
|
+
repoUrl: "gitlab.com",
|
|
668
|
+
path: ["group1"]
|
|
646
669
|
}
|
|
647
670
|
}
|
|
648
671
|
]
|
|
649
672
|
})
|
|
650
673
|
},
|
|
651
674
|
{
|
|
652
|
-
description: "Create a
|
|
675
|
+
description: "Create a group nested within another group",
|
|
653
676
|
example: yaml__default.default.stringify({
|
|
654
677
|
steps: [
|
|
655
678
|
{
|
|
656
|
-
id: "
|
|
657
|
-
|
|
658
|
-
|
|
679
|
+
id: "gitlabGroup",
|
|
680
|
+
name: "Group",
|
|
681
|
+
action: "gitlab:group:ensureExists",
|
|
659
682
|
input: {
|
|
660
|
-
repoUrl: "gitlab.com
|
|
661
|
-
|
|
662
|
-
key: "MY_VARIABLE",
|
|
663
|
-
value: "my_value",
|
|
664
|
-
variableType: "env_var",
|
|
665
|
-
raw: true
|
|
683
|
+
repoUrl: "gitlab.com",
|
|
684
|
+
path: ["group1", "group2"]
|
|
666
685
|
}
|
|
667
686
|
}
|
|
668
687
|
]
|
|
669
688
|
})
|
|
670
689
|
},
|
|
671
690
|
{
|
|
672
|
-
description: "Create a
|
|
691
|
+
description: "Create a group nested within multiple other groups",
|
|
673
692
|
example: yaml__default.default.stringify({
|
|
674
693
|
steps: [
|
|
675
694
|
{
|
|
676
|
-
id: "
|
|
677
|
-
|
|
678
|
-
|
|
695
|
+
id: "gitlabGroup",
|
|
696
|
+
name: "Group",
|
|
697
|
+
action: "gitlab:group:ensureExists",
|
|
679
698
|
input: {
|
|
680
|
-
repoUrl: "gitlab.com
|
|
681
|
-
|
|
682
|
-
key: "MY_VARIABLE",
|
|
683
|
-
value: "my_value",
|
|
684
|
-
variableType: "env_var",
|
|
685
|
-
environmentScope: "production"
|
|
699
|
+
repoUrl: "gitlab.com",
|
|
700
|
+
path: ["group1", "group2", "group3"]
|
|
686
701
|
}
|
|
687
702
|
}
|
|
688
703
|
]
|
|
689
704
|
})
|
|
690
705
|
},
|
|
691
706
|
{
|
|
692
|
-
description: "Create a
|
|
707
|
+
description: "Create a group in dry run mode",
|
|
693
708
|
example: yaml__default.default.stringify({
|
|
694
709
|
steps: [
|
|
695
710
|
{
|
|
696
|
-
id: "
|
|
697
|
-
|
|
698
|
-
|
|
711
|
+
id: "gitlabGroup",
|
|
712
|
+
name: "Group",
|
|
713
|
+
action: "gitlab:group:ensureExists",
|
|
714
|
+
isDryRun: true,
|
|
699
715
|
input: {
|
|
700
|
-
repoUrl: "gitlab.com
|
|
701
|
-
|
|
702
|
-
key: "MY_VARIABLE",
|
|
703
|
-
value: "my_value",
|
|
704
|
-
variableType: "env_var",
|
|
705
|
-
environmentScope: "*"
|
|
716
|
+
repoUrl: "https://gitlab.com/my-repo",
|
|
717
|
+
path: ["group1", "group2", "group3"]
|
|
706
718
|
}
|
|
707
719
|
}
|
|
708
720
|
]
|
|
@@ -710,61 +722,68 @@ const examples$4 = [
|
|
|
710
722
|
}
|
|
711
723
|
];
|
|
712
724
|
|
|
713
|
-
const
|
|
725
|
+
const createGitlabGroupEnsureExistsAction = (options) => {
|
|
714
726
|
const { integrations } = options;
|
|
715
727
|
return pluginScaffolderNode.createTemplateAction({
|
|
716
|
-
id: "gitlab:
|
|
717
|
-
|
|
728
|
+
id: "gitlab:group:ensureExists",
|
|
729
|
+
description: "Ensures a Gitlab group exists",
|
|
730
|
+
supportsDryRun: true,
|
|
731
|
+
examples: examples$7,
|
|
718
732
|
schema: {
|
|
719
733
|
input: commonGitlabConfig.merge(
|
|
720
734
|
zod.z.object({
|
|
721
|
-
|
|
722
|
-
description: "
|
|
723
|
-
})
|
|
724
|
-
key: zod.z.string({
|
|
725
|
-
description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed"
|
|
726
|
-
}).regex(/^[A-Za-z0-9_]{1,255}$/),
|
|
727
|
-
value: zod.z.string({ description: "The value of a variable" }),
|
|
728
|
-
variableType: zod.z.string({
|
|
729
|
-
description: "Variable Type (env_var or file)"
|
|
730
|
-
}),
|
|
731
|
-
variableProtected: zod.z.boolean({ description: "Whether the variable is protected" }).default(false).optional(),
|
|
732
|
-
masked: zod.z.boolean({ description: "Whether the variable is masked" }).default(false).optional(),
|
|
733
|
-
raw: zod.z.boolean({ description: "Whether the variable is expandable" }).default(false).optional(),
|
|
734
|
-
environmentScope: zod.z.string({ description: "The environment_scope of the variable" }).default("*").optional()
|
|
735
|
+
path: zod.z.array(zod.z.string(), {
|
|
736
|
+
description: "A path of group names that is ensured to exist"
|
|
737
|
+
}).min(1)
|
|
735
738
|
})
|
|
736
|
-
)
|
|
739
|
+
),
|
|
740
|
+
output: zod.z.object({
|
|
741
|
+
groupId: zod.z.number({ description: "The id of the innermost sub-group" }).optional()
|
|
742
|
+
})
|
|
737
743
|
},
|
|
738
744
|
async handler(ctx) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
variableProtected = false,
|
|
745
|
-
masked = false,
|
|
746
|
-
raw = false,
|
|
747
|
-
environmentScope = "*"
|
|
748
|
-
} = ctx.input;
|
|
745
|
+
if (ctx.isDryRun) {
|
|
746
|
+
ctx.output("groupId", 42);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const { path } = ctx.input;
|
|
749
750
|
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
750
751
|
const api = new node.Gitlab({
|
|
751
752
|
host: integrationConfig.config.baseUrl,
|
|
752
753
|
token
|
|
753
754
|
});
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
755
|
+
let currentPath = null;
|
|
756
|
+
let parent = null;
|
|
757
|
+
for (const pathElement of path) {
|
|
758
|
+
const fullPath = currentPath ? `${currentPath}/${pathElement}` : pathElement;
|
|
759
|
+
const result = await api.Groups.search(
|
|
760
|
+
fullPath
|
|
761
|
+
);
|
|
762
|
+
const subGroup = result.find(
|
|
763
|
+
(searchPathElem) => searchPathElem.full_path === fullPath
|
|
764
|
+
);
|
|
765
|
+
if (!subGroup) {
|
|
766
|
+
ctx.logger.info(`creating missing group ${fullPath}`);
|
|
767
|
+
parent = await api.Groups.create(
|
|
768
|
+
pathElement,
|
|
769
|
+
pathElement,
|
|
770
|
+
parent ? {
|
|
771
|
+
parent_id: parent.id
|
|
772
|
+
} : {}
|
|
773
|
+
);
|
|
774
|
+
} else {
|
|
775
|
+
parent = subGroup;
|
|
776
|
+
}
|
|
777
|
+
currentPath = fullPath;
|
|
778
|
+
}
|
|
779
|
+
if (parent !== null) {
|
|
780
|
+
ctx.output("groupId", parent?.id);
|
|
781
|
+
}
|
|
763
782
|
}
|
|
764
783
|
});
|
|
765
784
|
};
|
|
766
785
|
|
|
767
|
-
const examples$
|
|
786
|
+
const examples$6 = [
|
|
768
787
|
{
|
|
769
788
|
description: "Create a GitLab issue with minimal options",
|
|
770
789
|
example: yaml__default.default.stringify({
|
|
@@ -885,7 +904,7 @@ const createGitlabIssueAction = (options) => {
|
|
|
885
904
|
return pluginScaffolderNode.createTemplateAction({
|
|
886
905
|
id: "gitlab:issues:create",
|
|
887
906
|
description: "Creates a Gitlab issue.",
|
|
888
|
-
examples: examples$
|
|
907
|
+
examples: examples$6,
|
|
889
908
|
schema: {
|
|
890
909
|
input: commonGitlabConfig.merge(issueInputProperties),
|
|
891
910
|
output: issueOutputProperties
|
|
@@ -966,144 +985,356 @@ const createGitlabIssueAction = (options) => {
|
|
|
966
985
|
});
|
|
967
986
|
};
|
|
968
987
|
|
|
969
|
-
|
|
988
|
+
function createGitlabApi(options) {
|
|
989
|
+
const { integrations, token: providedToken, repoUrl } = options;
|
|
990
|
+
const { host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
|
|
991
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
992
|
+
if (!integrationConfig) {
|
|
993
|
+
throw new errors.InputError(
|
|
994
|
+
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
if (!integrationConfig.config.token && !providedToken) {
|
|
998
|
+
throw new errors.InputError(`No token available for host ${host}`);
|
|
999
|
+
}
|
|
1000
|
+
const token = providedToken ?? integrationConfig.config.token;
|
|
1001
|
+
const tokenType = providedToken ? "oauthToken" : "token";
|
|
1002
|
+
return new node.Gitlab({
|
|
1003
|
+
host: integrationConfig.config.baseUrl,
|
|
1004
|
+
[tokenType]: token
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const examples$5 = [
|
|
970
1009
|
{
|
|
971
|
-
description: "
|
|
1010
|
+
description: "Create a merge request with a specific assignee",
|
|
972
1011
|
example: yaml__default.default.stringify({
|
|
973
1012
|
steps: [
|
|
974
1013
|
{
|
|
975
|
-
id: "
|
|
976
|
-
action: "publish:gitlab",
|
|
977
|
-
name: "
|
|
1014
|
+
id: "createMergeRequest",
|
|
1015
|
+
action: "publish:gitlab:merge-request",
|
|
1016
|
+
name: "Create a Merge Request",
|
|
978
1017
|
input: {
|
|
979
|
-
repoUrl: "gitlab.com?repo=
|
|
1018
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1019
|
+
title: "Create my new MR",
|
|
1020
|
+
description: "This MR is really good",
|
|
1021
|
+
sourcePath: "./path/to/my/changes",
|
|
1022
|
+
branchName: "new-mr",
|
|
1023
|
+
assignee: "my-assignee"
|
|
980
1024
|
}
|
|
981
1025
|
}
|
|
982
1026
|
]
|
|
983
1027
|
})
|
|
984
1028
|
},
|
|
985
1029
|
{
|
|
986
|
-
description: "
|
|
1030
|
+
description: "Create a merge request with removal of source branch after merge",
|
|
987
1031
|
example: yaml__default.default.stringify({
|
|
988
1032
|
steps: [
|
|
989
1033
|
{
|
|
990
|
-
id: "
|
|
991
|
-
action: "publish:gitlab",
|
|
992
|
-
name: "
|
|
1034
|
+
id: "createMergeRequest",
|
|
1035
|
+
action: "publish:gitlab:merge-request",
|
|
1036
|
+
name: "Create a Merge Request",
|
|
993
1037
|
input: {
|
|
994
|
-
repoUrl: "gitlab.com?repo=
|
|
995
|
-
|
|
1038
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1039
|
+
title: "Create my new MR",
|
|
1040
|
+
description: "This MR is really good",
|
|
1041
|
+
sourcePath: "./path/to/my/changes",
|
|
1042
|
+
branchName: "new-mr",
|
|
1043
|
+
removeSourceBranch: true
|
|
996
1044
|
}
|
|
997
1045
|
}
|
|
998
1046
|
]
|
|
999
1047
|
})
|
|
1000
1048
|
},
|
|
1001
1049
|
{
|
|
1002
|
-
description: "
|
|
1050
|
+
description: "Create a merge request with a target branch",
|
|
1003
1051
|
example: yaml__default.default.stringify({
|
|
1004
1052
|
steps: [
|
|
1005
1053
|
{
|
|
1006
|
-
id: "
|
|
1007
|
-
action: "publish:gitlab",
|
|
1008
|
-
name: "
|
|
1054
|
+
id: "createMergeRequest",
|
|
1055
|
+
action: "publish:gitlab:merge-request",
|
|
1056
|
+
name: "Create a Merge Request",
|
|
1009
1057
|
input: {
|
|
1010
|
-
repoUrl: "gitlab.com?repo=
|
|
1011
|
-
|
|
1012
|
-
|
|
1058
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1059
|
+
title: "Create my new MR",
|
|
1060
|
+
description: "This MR is really good",
|
|
1061
|
+
sourcePath: "./path/to/my/changes",
|
|
1062
|
+
branchName: "new-mr",
|
|
1063
|
+
targetBranchName: "test",
|
|
1064
|
+
targetPath: "Subdirectory"
|
|
1013
1065
|
}
|
|
1014
1066
|
}
|
|
1015
1067
|
]
|
|
1016
1068
|
})
|
|
1017
1069
|
},
|
|
1018
1070
|
{
|
|
1019
|
-
description: "
|
|
1071
|
+
description: "Create a merge request with a commit action as create",
|
|
1020
1072
|
example: yaml__default.default.stringify({
|
|
1021
1073
|
steps: [
|
|
1022
1074
|
{
|
|
1023
|
-
id: "
|
|
1024
|
-
action: "publish:gitlab",
|
|
1025
|
-
name: "
|
|
1075
|
+
id: "createMergeRequest",
|
|
1076
|
+
action: "publish:gitlab:merge-request",
|
|
1077
|
+
name: "Create a Merge Request",
|
|
1026
1078
|
input: {
|
|
1027
|
-
repoUrl: "gitlab.com?repo=
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1079
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1080
|
+
title: "Create my new MR",
|
|
1081
|
+
branchName: "new-mr",
|
|
1082
|
+
description: "MR description",
|
|
1083
|
+
commitAction: "create",
|
|
1084
|
+
targetPath: "source"
|
|
1032
1085
|
}
|
|
1033
1086
|
}
|
|
1034
1087
|
]
|
|
1035
1088
|
})
|
|
1036
1089
|
},
|
|
1037
1090
|
{
|
|
1038
|
-
description: "
|
|
1091
|
+
description: "Create a merge request with a commit action as delete",
|
|
1039
1092
|
example: yaml__default.default.stringify({
|
|
1040
1093
|
steps: [
|
|
1041
1094
|
{
|
|
1042
|
-
id: "
|
|
1043
|
-
action: "publish:gitlab",
|
|
1044
|
-
name: "
|
|
1095
|
+
id: "createMergeRequest",
|
|
1096
|
+
action: "publish:gitlab:merge-request",
|
|
1097
|
+
name: "Create a Merge Request",
|
|
1045
1098
|
input: {
|
|
1046
|
-
repoUrl: "gitlab.com?repo=
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1099
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1100
|
+
title: "Create my new MR",
|
|
1101
|
+
branchName: "new-mr",
|
|
1102
|
+
description: "MR description",
|
|
1103
|
+
commitAction: "delete",
|
|
1104
|
+
targetPath: "source"
|
|
1051
1105
|
}
|
|
1052
1106
|
}
|
|
1053
1107
|
]
|
|
1054
1108
|
})
|
|
1055
1109
|
},
|
|
1056
1110
|
{
|
|
1057
|
-
description: "
|
|
1111
|
+
description: "Create a merge request with a commit action as update",
|
|
1058
1112
|
example: yaml__default.default.stringify({
|
|
1059
1113
|
steps: [
|
|
1060
1114
|
{
|
|
1061
|
-
id: "
|
|
1062
|
-
action: "publish:gitlab",
|
|
1063
|
-
name: "
|
|
1115
|
+
id: "createMergeRequest",
|
|
1116
|
+
action: "publish:gitlab:merge-request",
|
|
1117
|
+
name: "Create a Merge Request",
|
|
1064
1118
|
input: {
|
|
1065
|
-
repoUrl: "gitlab.com?repo=
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
ref: "master"
|
|
1072
|
-
},
|
|
1073
|
-
{
|
|
1074
|
-
name: "master",
|
|
1075
|
-
protected: true
|
|
1076
|
-
}
|
|
1077
|
-
]
|
|
1119
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1120
|
+
title: "Create my new MR",
|
|
1121
|
+
branchName: "new-mr",
|
|
1122
|
+
description: "MR description",
|
|
1123
|
+
commitAction: "update",
|
|
1124
|
+
targetPath: "source"
|
|
1078
1125
|
}
|
|
1079
1126
|
}
|
|
1080
1127
|
]
|
|
1081
1128
|
})
|
|
1082
|
-
}
|
|
1129
|
+
}
|
|
1130
|
+
];
|
|
1131
|
+
|
|
1132
|
+
const createPublishGitlabMergeRequestAction = (options) => {
|
|
1133
|
+
const { integrations } = options;
|
|
1134
|
+
return pluginScaffolderNode.createTemplateAction({
|
|
1135
|
+
id: "publish:gitlab:merge-request",
|
|
1136
|
+
examples: examples$5,
|
|
1137
|
+
schema: {
|
|
1138
|
+
input: {
|
|
1139
|
+
required: ["repoUrl", "branchName"],
|
|
1140
|
+
type: "object",
|
|
1141
|
+
properties: {
|
|
1142
|
+
repoUrl: {
|
|
1143
|
+
type: "string",
|
|
1144
|
+
title: "Repository Location",
|
|
1145
|
+
description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`
|
|
1146
|
+
},
|
|
1147
|
+
/** @deprecated projectID is passed as query parameters in the repoUrl */
|
|
1148
|
+
projectid: {
|
|
1149
|
+
type: "string",
|
|
1150
|
+
title: "projectid",
|
|
1151
|
+
description: "Project ID/Name(slug) of the Gitlab Project"
|
|
1152
|
+
},
|
|
1153
|
+
title: {
|
|
1154
|
+
type: "string",
|
|
1155
|
+
title: "Merge Request Name",
|
|
1156
|
+
description: "The name for the merge request"
|
|
1157
|
+
},
|
|
1158
|
+
description: {
|
|
1159
|
+
type: "string",
|
|
1160
|
+
title: "Merge Request Description",
|
|
1161
|
+
description: "The description of the merge request"
|
|
1162
|
+
},
|
|
1163
|
+
branchName: {
|
|
1164
|
+
type: "string",
|
|
1165
|
+
title: "Source Branch Name",
|
|
1166
|
+
description: "The source branch name of the merge request"
|
|
1167
|
+
},
|
|
1168
|
+
targetBranchName: {
|
|
1169
|
+
type: "string",
|
|
1170
|
+
title: "Target Branch Name",
|
|
1171
|
+
description: "The target branch name of the merge request"
|
|
1172
|
+
},
|
|
1173
|
+
sourcePath: {
|
|
1174
|
+
type: "string",
|
|
1175
|
+
title: "Working Subdirectory",
|
|
1176
|
+
description: "Subdirectory of working directory to copy changes from"
|
|
1177
|
+
},
|
|
1178
|
+
targetPath: {
|
|
1179
|
+
type: "string",
|
|
1180
|
+
title: "Repository Subdirectory",
|
|
1181
|
+
description: "Subdirectory of repository to apply changes to"
|
|
1182
|
+
},
|
|
1183
|
+
token: {
|
|
1184
|
+
title: "Authentication Token",
|
|
1185
|
+
type: "string",
|
|
1186
|
+
description: "The token to use for authorization to GitLab"
|
|
1187
|
+
},
|
|
1188
|
+
commitAction: {
|
|
1189
|
+
title: "Commit action",
|
|
1190
|
+
type: "string",
|
|
1191
|
+
enum: ["create", "update", "delete"],
|
|
1192
|
+
description: "The action to be used for git commit. Defaults to create."
|
|
1193
|
+
},
|
|
1194
|
+
removeSourceBranch: {
|
|
1195
|
+
title: "Delete source branch",
|
|
1196
|
+
type: "boolean",
|
|
1197
|
+
description: "Option to delete source branch once the MR has been merged. Default: false"
|
|
1198
|
+
},
|
|
1199
|
+
assignee: {
|
|
1200
|
+
title: "Merge Request Assignee",
|
|
1201
|
+
type: "string",
|
|
1202
|
+
description: "User this merge request will be assigned to"
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
},
|
|
1206
|
+
output: {
|
|
1207
|
+
type: "object",
|
|
1208
|
+
properties: {
|
|
1209
|
+
targetBranchName: {
|
|
1210
|
+
title: "Target branch name of the merge request",
|
|
1211
|
+
type: "string"
|
|
1212
|
+
},
|
|
1213
|
+
projectid: {
|
|
1214
|
+
title: "Gitlab Project id/Name(slug)",
|
|
1215
|
+
type: "string"
|
|
1216
|
+
},
|
|
1217
|
+
projectPath: {
|
|
1218
|
+
title: "Gitlab Project path",
|
|
1219
|
+
type: "string"
|
|
1220
|
+
},
|
|
1221
|
+
mergeRequestUrl: {
|
|
1222
|
+
title: "MergeRequest(MR) URL",
|
|
1223
|
+
type: "string",
|
|
1224
|
+
description: "Link to the merge request in GitLab"
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
async handler(ctx) {
|
|
1230
|
+
const {
|
|
1231
|
+
assignee,
|
|
1232
|
+
branchName,
|
|
1233
|
+
targetBranchName,
|
|
1234
|
+
description,
|
|
1235
|
+
repoUrl,
|
|
1236
|
+
removeSourceBranch,
|
|
1237
|
+
targetPath,
|
|
1238
|
+
sourcePath,
|
|
1239
|
+
title,
|
|
1240
|
+
token
|
|
1241
|
+
} = ctx.input;
|
|
1242
|
+
const { owner, repo, project } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
|
|
1243
|
+
const repoID = project ? project : `${owner}/${repo}`;
|
|
1244
|
+
const api = createGitlabApi({
|
|
1245
|
+
integrations,
|
|
1246
|
+
token,
|
|
1247
|
+
repoUrl
|
|
1248
|
+
});
|
|
1249
|
+
let assigneeId = void 0;
|
|
1250
|
+
if (assignee !== void 0) {
|
|
1251
|
+
try {
|
|
1252
|
+
const assigneeUser = await api.Users.username(assignee);
|
|
1253
|
+
assigneeId = assigneeUser[0].id;
|
|
1254
|
+
} catch (e) {
|
|
1255
|
+
ctx.logger.warn(
|
|
1256
|
+
`Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
let fileRoot;
|
|
1261
|
+
if (sourcePath) {
|
|
1262
|
+
fileRoot = backendPluginApi.resolveSafeChildPath(ctx.workspacePath, sourcePath);
|
|
1263
|
+
} else if (targetPath) {
|
|
1264
|
+
fileRoot = backendPluginApi.resolveSafeChildPath(ctx.workspacePath, targetPath);
|
|
1265
|
+
} else {
|
|
1266
|
+
fileRoot = ctx.workspacePath;
|
|
1267
|
+
}
|
|
1268
|
+
const fileContents = await pluginScaffolderNode.serializeDirectoryContents(fileRoot, {
|
|
1269
|
+
gitignore: true
|
|
1270
|
+
});
|
|
1271
|
+
const actions = fileContents.map((file) => ({
|
|
1272
|
+
action: ctx.input.commitAction ?? "create",
|
|
1273
|
+
filePath: targetPath ? path__default.default.posix.join(targetPath, file.path) : file.path,
|
|
1274
|
+
encoding: "base64",
|
|
1275
|
+
content: file.content.toString("base64"),
|
|
1276
|
+
execute_filemode: file.executable
|
|
1277
|
+
}));
|
|
1278
|
+
let targetBranch = targetBranchName;
|
|
1279
|
+
if (!targetBranch) {
|
|
1280
|
+
const projects = await api.Projects.show(repoID);
|
|
1281
|
+
const { default_branch: defaultBranch } = projects;
|
|
1282
|
+
targetBranch = defaultBranch;
|
|
1283
|
+
}
|
|
1284
|
+
try {
|
|
1285
|
+
await api.Branches.create(repoID, branchName, String(targetBranch));
|
|
1286
|
+
} catch (e) {
|
|
1287
|
+
throw new errors.InputError(
|
|
1288
|
+
`The branch creation failed. Please check that your repo does not already contain a branch named '${branchName}'. ${e}`
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
try {
|
|
1292
|
+
await api.Commits.create(repoID, branchName, ctx.input.title, actions);
|
|
1293
|
+
} catch (e) {
|
|
1294
|
+
throw new errors.InputError(
|
|
1295
|
+
`Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${e}`
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
try {
|
|
1299
|
+
const mergeRequestUrl = await api.MergeRequests.create(
|
|
1300
|
+
repoID,
|
|
1301
|
+
branchName,
|
|
1302
|
+
String(targetBranch),
|
|
1303
|
+
title,
|
|
1304
|
+
{
|
|
1305
|
+
description,
|
|
1306
|
+
removeSourceBranch: removeSourceBranch ? removeSourceBranch : false,
|
|
1307
|
+
assigneeId
|
|
1308
|
+
}
|
|
1309
|
+
).then((mergeRequest) => {
|
|
1310
|
+
return mergeRequest.web_url;
|
|
1311
|
+
});
|
|
1312
|
+
ctx.output("projectid", repoID);
|
|
1313
|
+
ctx.output("targetBranchName", targetBranch);
|
|
1314
|
+
ctx.output("projectPath", repoID);
|
|
1315
|
+
ctx.output("mergeRequestUrl", mergeRequestUrl);
|
|
1316
|
+
} catch (e) {
|
|
1317
|
+
throw new errors.InputError(`Merge request creation failed${e}`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
const examples$4 = [
|
|
1083
1324
|
{
|
|
1084
|
-
description: "
|
|
1325
|
+
description: "Trigger a GitLab Project Pipeline",
|
|
1085
1326
|
example: yaml__default.default.stringify({
|
|
1086
1327
|
steps: [
|
|
1087
1328
|
{
|
|
1088
|
-
id: "
|
|
1089
|
-
|
|
1090
|
-
|
|
1329
|
+
id: "triggerPipeline",
|
|
1330
|
+
name: "Trigger Project Pipeline",
|
|
1331
|
+
action: "gitlab:pipeline:trigger",
|
|
1091
1332
|
input: {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
protected: true,
|
|
1098
|
-
masked: false
|
|
1099
|
-
},
|
|
1100
|
-
{
|
|
1101
|
-
key: "key2",
|
|
1102
|
-
value: "value2",
|
|
1103
|
-
protected: true,
|
|
1104
|
-
masked: false
|
|
1105
|
-
}
|
|
1106
|
-
]
|
|
1333
|
+
...commonGitlabConfigExample,
|
|
1334
|
+
projectId: 12,
|
|
1335
|
+
tokenDescription: "This is the text that will appear in the pipeline token",
|
|
1336
|
+
token: "glpt-xxxxxxxxxxxx",
|
|
1337
|
+
branch: "main"
|
|
1107
1338
|
}
|
|
1108
1339
|
}
|
|
1109
1340
|
]
|
|
@@ -1111,509 +1342,509 @@ const examples$2 = [
|
|
|
1111
1342
|
}
|
|
1112
1343
|
];
|
|
1113
1344
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1345
|
+
const pipelineInputProperties = zod.z.object({
|
|
1346
|
+
projectId: zod.z.number().describe("Project Id"),
|
|
1347
|
+
tokenDescription: zod.z.string().describe("Pipeline token description"),
|
|
1348
|
+
branch: zod.z.string().describe("Project branch")
|
|
1349
|
+
});
|
|
1350
|
+
const pipelineOutputProperties = zod.z.object({
|
|
1351
|
+
pipelineUrl: zod.z.string({ description: "Pipeline Url" })
|
|
1352
|
+
});
|
|
1353
|
+
const createTriggerGitlabPipelineAction = (options) => {
|
|
1354
|
+
const { integrations } = options;
|
|
1116
1355
|
return pluginScaffolderNode.createTemplateAction({
|
|
1117
|
-
id: "
|
|
1118
|
-
description: "
|
|
1119
|
-
examples: examples$
|
|
1356
|
+
id: "gitlab:pipeline:trigger",
|
|
1357
|
+
description: "Triggers a GitLab Pipeline.",
|
|
1358
|
+
examples: examples$4,
|
|
1120
1359
|
schema: {
|
|
1121
|
-
input:
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
type: "boolean"
|
|
1193
|
-
},
|
|
1194
|
-
ci_config_path: {
|
|
1195
|
-
title: "CI config path",
|
|
1196
|
-
description: "Custom CI config path for this project",
|
|
1197
|
-
type: "string"
|
|
1198
|
-
},
|
|
1199
|
-
description: {
|
|
1200
|
-
title: "Project description",
|
|
1201
|
-
description: "Short project description",
|
|
1202
|
-
type: "string"
|
|
1203
|
-
},
|
|
1204
|
-
merge_method: {
|
|
1205
|
-
title: "Merge Method to use",
|
|
1206
|
-
description: "Merge Methods (merge, rebase_merge, ff)",
|
|
1207
|
-
type: "string",
|
|
1208
|
-
enum: ["merge", "rebase_merge", "ff"]
|
|
1209
|
-
},
|
|
1210
|
-
squash_option: {
|
|
1211
|
-
title: "Squash option",
|
|
1212
|
-
description: "Set squash option for the project (never, always, default_on, default_off)",
|
|
1213
|
-
type: "string",
|
|
1214
|
-
enum: ["default_off", "default_on", "never", "always"]
|
|
1215
|
-
},
|
|
1216
|
-
topics: {
|
|
1217
|
-
title: "Topic labels",
|
|
1218
|
-
description: "Topic labels to apply on the repository",
|
|
1219
|
-
type: "array",
|
|
1220
|
-
items: {
|
|
1221
|
-
type: "string"
|
|
1222
|
-
}
|
|
1223
|
-
},
|
|
1224
|
-
visibility: {
|
|
1225
|
-
title: "Project visibility",
|
|
1226
|
-
description: "The visibility of the project. Can be private, internal, or public. The default value is private.",
|
|
1227
|
-
type: "string",
|
|
1228
|
-
enum: ["private", "public", "internal"]
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
},
|
|
1232
|
-
branches: {
|
|
1233
|
-
title: "Project branches settings",
|
|
1234
|
-
type: "array",
|
|
1235
|
-
items: {
|
|
1236
|
-
type: "object",
|
|
1237
|
-
required: ["name"],
|
|
1238
|
-
properties: {
|
|
1239
|
-
name: {
|
|
1240
|
-
title: "Branch name",
|
|
1241
|
-
type: "string"
|
|
1242
|
-
},
|
|
1243
|
-
protect: {
|
|
1244
|
-
title: "Should branch be protected",
|
|
1245
|
-
description: `Will mark branch as protected. The default value is 'false'`,
|
|
1246
|
-
type: "boolean"
|
|
1247
|
-
},
|
|
1248
|
-
create: {
|
|
1249
|
-
title: "Should branch be created",
|
|
1250
|
-
description: `If branch does not exist, it will be created from provided ref. The default value is 'false'`,
|
|
1251
|
-
type: "boolean"
|
|
1252
|
-
},
|
|
1253
|
-
ref: {
|
|
1254
|
-
title: "Branch reference",
|
|
1255
|
-
description: `Branch reference to create branch from. The default value is 'master'`,
|
|
1256
|
-
type: "string"
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
},
|
|
1261
|
-
projectVariables: {
|
|
1262
|
-
title: "Project variables",
|
|
1263
|
-
description: "Project variables settings based on Gitlab Project Environments API - https://docs.gitlab.com/ee/api/project_level_variables.html#create-a-variable",
|
|
1264
|
-
type: "array",
|
|
1265
|
-
items: {
|
|
1266
|
-
type: "object",
|
|
1267
|
-
required: ["key", "value"],
|
|
1268
|
-
properties: {
|
|
1269
|
-
key: {
|
|
1270
|
-
title: "Variable key",
|
|
1271
|
-
description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed",
|
|
1272
|
-
type: "string"
|
|
1273
|
-
},
|
|
1274
|
-
value: {
|
|
1275
|
-
title: "Variable value",
|
|
1276
|
-
description: "The value of a variable",
|
|
1277
|
-
type: "string"
|
|
1278
|
-
},
|
|
1279
|
-
description: {
|
|
1280
|
-
title: "Variable description",
|
|
1281
|
-
description: `The description of the variable. The default value is 'null'`,
|
|
1282
|
-
type: "string"
|
|
1283
|
-
},
|
|
1284
|
-
variable_type: {
|
|
1285
|
-
title: "Variable type",
|
|
1286
|
-
description: `The type of a variable. The default value is 'env_var'`,
|
|
1287
|
-
type: "string",
|
|
1288
|
-
enum: ["env_var", "file"]
|
|
1289
|
-
},
|
|
1290
|
-
protected: {
|
|
1291
|
-
title: "Variable protection",
|
|
1292
|
-
description: `Whether the variable is protected. The default value is 'false'`,
|
|
1293
|
-
type: "boolean"
|
|
1294
|
-
},
|
|
1295
|
-
raw: {
|
|
1296
|
-
title: "Variable raw",
|
|
1297
|
-
description: `Whether the variable is in raw format. The default value is 'false'`,
|
|
1298
|
-
type: "boolean"
|
|
1299
|
-
},
|
|
1300
|
-
environment_scope: {
|
|
1301
|
-
title: "Variable environment scope",
|
|
1302
|
-
description: `The environment_scope of the variable. The default value is '*'`,
|
|
1303
|
-
type: "string"
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1360
|
+
input: commonGitlabConfig.merge(pipelineInputProperties),
|
|
1361
|
+
output: pipelineOutputProperties
|
|
1362
|
+
},
|
|
1363
|
+
async handler(ctx) {
|
|
1364
|
+
let pipelineTokenResponse = null;
|
|
1365
|
+
const { repoUrl, projectId, tokenDescription, token, branch } = commonGitlabConfig.merge(pipelineInputProperties).parse(ctx.input);
|
|
1366
|
+
const { host } = parseRepoUrl(repoUrl, integrations);
|
|
1367
|
+
const api = getClient({ host, integrations, token });
|
|
1368
|
+
try {
|
|
1369
|
+
pipelineTokenResponse = await api.PipelineTriggerTokens.create(
|
|
1370
|
+
projectId,
|
|
1371
|
+
tokenDescription
|
|
1372
|
+
);
|
|
1373
|
+
if (!pipelineTokenResponse.token) {
|
|
1374
|
+
ctx.logger.error("Failed to create pipeline token.");
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
ctx.logger.info(
|
|
1378
|
+
`Pipeline token id ${pipelineTokenResponse.id} created.`
|
|
1379
|
+
);
|
|
1380
|
+
const pipelineTriggerResponse = await api.PipelineTriggerTokens.trigger(
|
|
1381
|
+
projectId,
|
|
1382
|
+
branch,
|
|
1383
|
+
pipelineTokenResponse.token
|
|
1384
|
+
);
|
|
1385
|
+
if (!pipelineTriggerResponse.id) {
|
|
1386
|
+
ctx.logger.error("Failed to trigger pipeline.");
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
ctx.logger.info(`Pipeline id ${pipelineTriggerResponse.id} triggered.`);
|
|
1390
|
+
ctx.output("pipelineUrl", pipelineTriggerResponse.web_url);
|
|
1391
|
+
} catch (error) {
|
|
1392
|
+
if (error instanceof zod.z.ZodError) {
|
|
1393
|
+
throw new errors.InputError(`Validation error: ${error.message}`, {
|
|
1394
|
+
validationErrors: error.errors
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
throw new errors.InputError(`Failed to trigger Pipeline: ${error.message}`);
|
|
1398
|
+
} finally {
|
|
1399
|
+
if (pipelineTokenResponse && pipelineTokenResponse.id) {
|
|
1400
|
+
try {
|
|
1401
|
+
await api.PipelineTriggerTokens.remove(
|
|
1402
|
+
projectId,
|
|
1403
|
+
pipelineTokenResponse.id
|
|
1404
|
+
);
|
|
1405
|
+
ctx.logger.info(
|
|
1406
|
+
`Deleted pipeline token ${pipelineTokenResponse.id}.`
|
|
1407
|
+
);
|
|
1408
|
+
} catch (error) {
|
|
1409
|
+
ctx.logger.error(
|
|
1410
|
+
`Failed to delete pipeline token id ${pipelineTokenResponse.id}.`
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
const examples$3 = [
|
|
1420
|
+
{
|
|
1421
|
+
description: "Create a GitLab project access token with minimal options.",
|
|
1422
|
+
example: yaml__default.default.stringify({
|
|
1423
|
+
steps: [
|
|
1424
|
+
{
|
|
1425
|
+
id: "createAccessToken",
|
|
1426
|
+
action: "gitlab:projectAccessToken:create",
|
|
1427
|
+
name: "Create GitLab Project Access Token",
|
|
1428
|
+
input: {
|
|
1429
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1430
|
+
projectId: "456"
|
|
1307
1431
|
}
|
|
1308
1432
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
},
|
|
1325
|
-
commitHash: {
|
|
1326
|
-
title: "The git commit hash of the initial commit",
|
|
1327
|
-
type: "string"
|
|
1433
|
+
]
|
|
1434
|
+
})
|
|
1435
|
+
},
|
|
1436
|
+
{
|
|
1437
|
+
description: "Create a GitLab project access token with custom scopes.",
|
|
1438
|
+
example: yaml__default.default.stringify({
|
|
1439
|
+
steps: [
|
|
1440
|
+
{
|
|
1441
|
+
id: "createAccessToken",
|
|
1442
|
+
action: "gitlab:projectAccessToken:create",
|
|
1443
|
+
name: "Create GitLab Project Access Token",
|
|
1444
|
+
input: {
|
|
1445
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1446
|
+
projectId: "789",
|
|
1447
|
+
scopes: ["read_registry", "write_repository"]
|
|
1328
1448
|
}
|
|
1329
1449
|
}
|
|
1330
|
-
|
|
1450
|
+
]
|
|
1451
|
+
})
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
description: "Create a GitLab project access token with a specified name.",
|
|
1455
|
+
example: yaml__default.default.stringify({
|
|
1456
|
+
steps: [
|
|
1457
|
+
{
|
|
1458
|
+
id: "createAccessToken",
|
|
1459
|
+
action: "gitlab:projectAccessToken:create",
|
|
1460
|
+
name: "Create GitLab Project Access Token",
|
|
1461
|
+
input: {
|
|
1462
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1463
|
+
projectId: "101112",
|
|
1464
|
+
name: "my-custom-token"
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
]
|
|
1468
|
+
})
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
description: "Create a GitLab project access token with a numeric project ID.",
|
|
1472
|
+
example: yaml__default.default.stringify({
|
|
1473
|
+
steps: [
|
|
1474
|
+
{
|
|
1475
|
+
id: "createAccessToken",
|
|
1476
|
+
action: "gitlab:projectAccessToken:create",
|
|
1477
|
+
name: "Create GitLab Project Access Token",
|
|
1478
|
+
input: {
|
|
1479
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1480
|
+
projectId: 42
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
]
|
|
1484
|
+
})
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
description: "Create a GitLab project access token with a specified expired Date.",
|
|
1488
|
+
example: yaml__default.default.stringify({
|
|
1489
|
+
steps: [
|
|
1490
|
+
{
|
|
1491
|
+
id: "createAccessToken",
|
|
1492
|
+
action: "gitlab:projectAccessToken:create",
|
|
1493
|
+
name: "Create GitLab Project Access Token",
|
|
1494
|
+
input: {
|
|
1495
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1496
|
+
projectId: "123",
|
|
1497
|
+
expiresAt: "2024-06-25"
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
]
|
|
1501
|
+
})
|
|
1502
|
+
}
|
|
1503
|
+
];
|
|
1504
|
+
|
|
1505
|
+
const createGitlabProjectAccessTokenAction = (options) => {
|
|
1506
|
+
const { integrations } = options;
|
|
1507
|
+
return pluginScaffolderNode.createTemplateAction({
|
|
1508
|
+
id: "gitlab:projectAccessToken:create",
|
|
1509
|
+
examples: examples$3,
|
|
1510
|
+
schema: {
|
|
1511
|
+
input: zod.z.object({
|
|
1512
|
+
projectId: zod.z.union([zod.z.number(), zod.z.string()], {
|
|
1513
|
+
description: "Project ID/Name(slug) of the Gitlab Project"
|
|
1514
|
+
}),
|
|
1515
|
+
token: zod.z.string({
|
|
1516
|
+
description: "The token to use for authorization to GitLab"
|
|
1517
|
+
}).optional(),
|
|
1518
|
+
name: zod.z.string({ description: "Name of Access Key" }).optional(),
|
|
1519
|
+
repoUrl: zod.z.string({ description: "URL to gitlab instance" }),
|
|
1520
|
+
accessLevel: zod.z.number({
|
|
1521
|
+
description: "Access Level of the Token, 10 (Guest), 20 (Reporter), 30 (Developer), 40 (Maintainer), and 50 (Owner)"
|
|
1522
|
+
}).optional(),
|
|
1523
|
+
scopes: zod.z.string({
|
|
1524
|
+
description: "Scopes for a project access token"
|
|
1525
|
+
}).array().optional(),
|
|
1526
|
+
expiresAt: zod.z.string({
|
|
1527
|
+
description: "Expiration date of the access token in ISO format (YYYY-MM-DD). If Empty, it will set to the maximum of 365 days."
|
|
1528
|
+
}).optional()
|
|
1529
|
+
}),
|
|
1530
|
+
output: zod.z.object({
|
|
1531
|
+
access_token: zod.z.string({ description: "Access Token" })
|
|
1532
|
+
})
|
|
1331
1533
|
},
|
|
1332
1534
|
async handler(ctx) {
|
|
1333
|
-
|
|
1535
|
+
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
|
1334
1536
|
const {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
gitAuthorEmail,
|
|
1341
|
-
setUserAsOwner = false,
|
|
1342
|
-
topics = [],
|
|
1343
|
-
settings = {},
|
|
1344
|
-
branches = [],
|
|
1345
|
-
projectVariables = []
|
|
1537
|
+
projectId,
|
|
1538
|
+
name = "tokenname",
|
|
1539
|
+
accessLevel = 40,
|
|
1540
|
+
scopes = ["read_repository"],
|
|
1541
|
+
expiresAt
|
|
1346
1542
|
} = ctx.input;
|
|
1347
|
-
const {
|
|
1348
|
-
if (!
|
|
1349
|
-
throw new errors.InputError(
|
|
1350
|
-
`No owner provided for host: ${host}, and repo ${repo}`
|
|
1351
|
-
);
|
|
1352
|
-
}
|
|
1353
|
-
const integrationConfig = integrations.gitlab.byHost(host);
|
|
1354
|
-
if (!integrationConfig) {
|
|
1543
|
+
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
1544
|
+
if (!integrationConfig.config.token && token) {
|
|
1355
1545
|
throw new errors.InputError(
|
|
1356
|
-
`No
|
|
1546
|
+
`No token available for host ${integrationConfig.config.baseUrl}`
|
|
1357
1547
|
);
|
|
1358
1548
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
const token = ctx.input.token || integrationConfig.config.token;
|
|
1363
|
-
const tokenType = ctx.input.token ? "oauthToken" : "token";
|
|
1364
|
-
const client = new node.Gitlab({
|
|
1365
|
-
host: integrationConfig.config.baseUrl,
|
|
1366
|
-
[tokenType]: token
|
|
1367
|
-
});
|
|
1368
|
-
let targetNamespaceId;
|
|
1369
|
-
try {
|
|
1370
|
-
const namespaceResponse = await client.Namespaces.show(owner);
|
|
1371
|
-
targetNamespaceId = namespaceResponse.id;
|
|
1372
|
-
} catch (e) {
|
|
1373
|
-
if (e.response && e.response.statusCode === 404) {
|
|
1374
|
-
throw new errors.InputError(
|
|
1375
|
-
`The namespace ${owner} is not found or the user doesn't have permissions to access it`
|
|
1376
|
-
);
|
|
1377
|
-
}
|
|
1378
|
-
throw e;
|
|
1379
|
-
}
|
|
1380
|
-
const { id: userId } = await client.Users.current();
|
|
1381
|
-
if (!targetNamespaceId) {
|
|
1382
|
-
targetNamespaceId = userId;
|
|
1383
|
-
}
|
|
1384
|
-
const { id: projectId, http_url_to_repo } = await client.Projects.create({
|
|
1385
|
-
namespace_id: targetNamespaceId,
|
|
1386
|
-
name: repo,
|
|
1387
|
-
visibility: repoVisibility,
|
|
1388
|
-
...topics.length ? { topics } : {},
|
|
1389
|
-
...Object.keys(settings).length ? { ...settings } : {}
|
|
1390
|
-
});
|
|
1391
|
-
if (setUserAsOwner && integrationConfig.config.token) {
|
|
1392
|
-
const adminClient = new node.Gitlab({
|
|
1549
|
+
let api;
|
|
1550
|
+
if (!ctx.input.token) {
|
|
1551
|
+
api = new rest.Gitlab({
|
|
1393
1552
|
host: integrationConfig.config.baseUrl,
|
|
1394
|
-
token
|
|
1553
|
+
token
|
|
1554
|
+
});
|
|
1555
|
+
} else {
|
|
1556
|
+
api = new rest.Gitlab({
|
|
1557
|
+
host: integrationConfig.config.baseUrl,
|
|
1558
|
+
oauthToken: token
|
|
1395
1559
|
});
|
|
1396
|
-
await adminClient.ProjectMembers.add(projectId, userId, 50);
|
|
1397
1560
|
}
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
throw new errors.InputError(
|
|
1429
|
-
`Branch creation failed for ${name}. ${printGitlabError(e)}`
|
|
1430
|
-
);
|
|
1431
|
-
}
|
|
1432
|
-
ctx.logger.info(
|
|
1433
|
-
`Branch ${name} created for ${projectId} with ref ${ref}`
|
|
1434
|
-
);
|
|
1561
|
+
const response = await api.ProjectAccessTokens.create(
|
|
1562
|
+
projectId,
|
|
1563
|
+
name,
|
|
1564
|
+
scopes,
|
|
1565
|
+
{
|
|
1566
|
+
expiresAt: expiresAt || luxon.DateTime.now().plus({ days: 365 }).toISODate(),
|
|
1567
|
+
accessLevel
|
|
1568
|
+
}
|
|
1569
|
+
);
|
|
1570
|
+
if (!response.token) {
|
|
1571
|
+
throw new Error("Could not create project access token");
|
|
1572
|
+
}
|
|
1573
|
+
ctx.output("access_token", response.token);
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
const examples$2 = [
|
|
1579
|
+
{
|
|
1580
|
+
description: "Create a GitLab project deploy token with minimal options.",
|
|
1581
|
+
example: yaml__default.default.stringify({
|
|
1582
|
+
steps: [
|
|
1583
|
+
{
|
|
1584
|
+
id: "createDeployToken",
|
|
1585
|
+
action: "gitlab:projectDeployToken:create",
|
|
1586
|
+
name: "Create GitLab Project Deploy Token",
|
|
1587
|
+
input: {
|
|
1588
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1589
|
+
projectId: "456",
|
|
1590
|
+
name: "tokenname"
|
|
1435
1591
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1592
|
+
}
|
|
1593
|
+
]
|
|
1594
|
+
})
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
description: "Create a GitLab project deploy token with custom scopes.",
|
|
1598
|
+
example: yaml__default.default.stringify({
|
|
1599
|
+
steps: [
|
|
1600
|
+
{
|
|
1601
|
+
id: "createDeployToken",
|
|
1602
|
+
action: "gitlab:projectDeployToken:create",
|
|
1603
|
+
name: "Create GitLab Project Deploy Token",
|
|
1604
|
+
input: {
|
|
1605
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1606
|
+
projectId: "789",
|
|
1607
|
+
name: "tokenname",
|
|
1608
|
+
scopes: ["read_registry", "write_repository"]
|
|
1445
1609
|
}
|
|
1446
1610
|
}
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1611
|
+
]
|
|
1612
|
+
})
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
description: "Create a GitLab project deploy token with a specified name.",
|
|
1616
|
+
example: yaml__default.default.stringify({
|
|
1617
|
+
steps: [
|
|
1618
|
+
{
|
|
1619
|
+
id: "createDeployToken",
|
|
1620
|
+
action: "gitlab:projectDeployToken:create",
|
|
1621
|
+
name: "Create GitLab Project Deploy Token",
|
|
1622
|
+
input: {
|
|
1623
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1624
|
+
projectId: "101112",
|
|
1625
|
+
name: "my-custom-token"
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
]
|
|
1629
|
+
})
|
|
1630
|
+
},
|
|
1631
|
+
{
|
|
1632
|
+
description: "Create a GitLab project deploy token with a numeric project ID.",
|
|
1633
|
+
example: yaml__default.default.stringify({
|
|
1634
|
+
steps: [
|
|
1635
|
+
{
|
|
1636
|
+
id: "createDeployToken",
|
|
1637
|
+
action: "gitlab:projectDeployToken:create",
|
|
1638
|
+
name: "Create GitLab Project Deploy Token",
|
|
1639
|
+
input: {
|
|
1640
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1641
|
+
projectId: 42,
|
|
1642
|
+
name: "tokenname"
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
]
|
|
1646
|
+
})
|
|
1647
|
+
},
|
|
1648
|
+
{
|
|
1649
|
+
description: "Create a GitLab project deploy token with a custom username",
|
|
1650
|
+
example: yaml__default.default.stringify({
|
|
1651
|
+
steps: [
|
|
1652
|
+
{
|
|
1653
|
+
id: "createDeployToken",
|
|
1654
|
+
action: "gitlab:projectDeployToken:create",
|
|
1655
|
+
name: "Create GitLab Project Deploy Token",
|
|
1656
|
+
input: {
|
|
1657
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1658
|
+
projectId: 42,
|
|
1659
|
+
name: "tokenname",
|
|
1660
|
+
username: "tokenuser"
|
|
1466
1661
|
}
|
|
1467
1662
|
}
|
|
1663
|
+
]
|
|
1664
|
+
})
|
|
1665
|
+
}
|
|
1666
|
+
];
|
|
1667
|
+
|
|
1668
|
+
const createGitlabProjectDeployTokenAction = (options) => {
|
|
1669
|
+
const { integrations } = options;
|
|
1670
|
+
return pluginScaffolderNode.createTemplateAction({
|
|
1671
|
+
id: "gitlab:projectDeployToken:create",
|
|
1672
|
+
examples: examples$2,
|
|
1673
|
+
schema: {
|
|
1674
|
+
input: commonGitlabConfig.merge(
|
|
1675
|
+
zod.z.object({
|
|
1676
|
+
projectId: zod.z.union([zod.z.number(), zod.z.string()], {
|
|
1677
|
+
description: "Project ID"
|
|
1678
|
+
}),
|
|
1679
|
+
name: zod.z.string({ description: "Deploy Token Name" }),
|
|
1680
|
+
username: zod.z.string({ description: "Deploy Token Username" }).optional(),
|
|
1681
|
+
scopes: zod.z.array(zod.z.string(), { description: "Scopes" }).optional()
|
|
1682
|
+
})
|
|
1683
|
+
),
|
|
1684
|
+
output: zod.z.object({
|
|
1685
|
+
deploy_token: zod.z.string({ description: "Deploy Token" }),
|
|
1686
|
+
user: zod.z.string({ description: "User" })
|
|
1687
|
+
})
|
|
1688
|
+
},
|
|
1689
|
+
async handler(ctx) {
|
|
1690
|
+
ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
|
|
1691
|
+
const { projectId, name, username, scopes } = ctx.input;
|
|
1692
|
+
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
1693
|
+
const api = new node.Gitlab({
|
|
1694
|
+
host: integrationConfig.config.baseUrl,
|
|
1695
|
+
token
|
|
1696
|
+
});
|
|
1697
|
+
const deployToken = await api.ProjectDeployTokens.add(
|
|
1698
|
+
projectId,
|
|
1699
|
+
name,
|
|
1700
|
+
scopes,
|
|
1701
|
+
{
|
|
1702
|
+
username
|
|
1703
|
+
}
|
|
1704
|
+
);
|
|
1705
|
+
if (!deployToken.hasOwnProperty("token")) {
|
|
1706
|
+
throw new errors.InputError(`No deploy_token given from gitlab instance`);
|
|
1468
1707
|
}
|
|
1469
|
-
ctx.output("
|
|
1470
|
-
ctx.output("
|
|
1471
|
-
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1472
|
-
ctx.output("projectId", projectId);
|
|
1708
|
+
ctx.output("deploy_token", deployToken.token);
|
|
1709
|
+
ctx.output("user", deployToken.username);
|
|
1473
1710
|
}
|
|
1474
1711
|
});
|
|
1475
|
-
}
|
|
1476
|
-
function printGitlabError(error) {
|
|
1477
|
-
return JSON.stringify({ code: error.code, message: error.description });
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
function createGitlabApi(options) {
|
|
1481
|
-
const { integrations, token: providedToken, repoUrl } = options;
|
|
1482
|
-
const { host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
|
|
1483
|
-
const integrationConfig = integrations.gitlab.byHost(host);
|
|
1484
|
-
if (!integrationConfig) {
|
|
1485
|
-
throw new errors.InputError(
|
|
1486
|
-
`No matching integration configuration for host ${host}, please check your integrations config`
|
|
1487
|
-
);
|
|
1488
|
-
}
|
|
1489
|
-
if (!integrationConfig.config.token && !providedToken) {
|
|
1490
|
-
throw new errors.InputError(`No token available for host ${host}`);
|
|
1491
|
-
}
|
|
1492
|
-
const token = providedToken != null ? providedToken : integrationConfig.config.token;
|
|
1493
|
-
const tokenType = providedToken ? "oauthToken" : "token";
|
|
1494
|
-
return new node.Gitlab({
|
|
1495
|
-
host: integrationConfig.config.baseUrl,
|
|
1496
|
-
[tokenType]: token
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1712
|
+
};
|
|
1499
1713
|
|
|
1500
1714
|
const examples$1 = [
|
|
1501
1715
|
{
|
|
1502
|
-
description: "
|
|
1716
|
+
description: "Creating a GitLab project variable of type env_var",
|
|
1503
1717
|
example: yaml__default.default.stringify({
|
|
1504
1718
|
steps: [
|
|
1505
1719
|
{
|
|
1506
|
-
id: "
|
|
1507
|
-
action: "
|
|
1508
|
-
name: "Create
|
|
1720
|
+
id: "createVariable",
|
|
1721
|
+
action: "gitlab:createGitlabProjectVariableAction",
|
|
1722
|
+
name: "Create GitLab Project Variable",
|
|
1509
1723
|
input: {
|
|
1510
1724
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
assignee: "my-assignee"
|
|
1725
|
+
projectId: "123",
|
|
1726
|
+
key: "MY_VARIABLE",
|
|
1727
|
+
value: "my_value",
|
|
1728
|
+
variableType: "env_var"
|
|
1516
1729
|
}
|
|
1517
1730
|
}
|
|
1518
1731
|
]
|
|
1519
1732
|
})
|
|
1520
1733
|
},
|
|
1521
1734
|
{
|
|
1522
|
-
description: "
|
|
1735
|
+
description: "Creating a GitLab project variable of type file",
|
|
1523
1736
|
example: yaml__default.default.stringify({
|
|
1524
1737
|
steps: [
|
|
1525
1738
|
{
|
|
1526
|
-
id: "
|
|
1527
|
-
action: "
|
|
1528
|
-
name: "Create
|
|
1739
|
+
id: "createVariable",
|
|
1740
|
+
action: "gitlab:createGitlabProjectVariableAction",
|
|
1741
|
+
name: "Create GitLab Project Variable",
|
|
1529
1742
|
input: {
|
|
1530
1743
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
removeSourceBranch: true
|
|
1744
|
+
projectId: "123",
|
|
1745
|
+
key: "MY_VARIABLE",
|
|
1746
|
+
value: "my-file-content",
|
|
1747
|
+
variableType: "file"
|
|
1536
1748
|
}
|
|
1537
1749
|
}
|
|
1538
1750
|
]
|
|
1539
1751
|
})
|
|
1540
1752
|
},
|
|
1541
1753
|
{
|
|
1542
|
-
description: "Create a
|
|
1754
|
+
description: "Create a GitLab project variable that is protected.",
|
|
1543
1755
|
example: yaml__default.default.stringify({
|
|
1544
1756
|
steps: [
|
|
1545
1757
|
{
|
|
1546
|
-
id: "
|
|
1547
|
-
action: "
|
|
1548
|
-
name: "Create
|
|
1758
|
+
id: "createVariable",
|
|
1759
|
+
action: "gitlab:createGitlabProjectVariableAction",
|
|
1760
|
+
name: "Create GitLab Project Variable",
|
|
1549
1761
|
input: {
|
|
1550
1762
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
targetPath: "Subdirectory"
|
|
1763
|
+
projectId: "456",
|
|
1764
|
+
key: "MY_VARIABLE",
|
|
1765
|
+
value: "my_value",
|
|
1766
|
+
variableType: "env_var",
|
|
1767
|
+
variableProtected: true
|
|
1557
1768
|
}
|
|
1558
1769
|
}
|
|
1559
1770
|
]
|
|
1560
1771
|
})
|
|
1561
1772
|
},
|
|
1562
1773
|
{
|
|
1563
|
-
description: "Create a
|
|
1774
|
+
description: "Create a GitLab project variable with masked flag as true",
|
|
1564
1775
|
example: yaml__default.default.stringify({
|
|
1565
1776
|
steps: [
|
|
1566
1777
|
{
|
|
1567
|
-
id: "
|
|
1568
|
-
action: "
|
|
1569
|
-
name: "Create
|
|
1778
|
+
id: "createVariable",
|
|
1779
|
+
action: "gitlab:createGitlabProjectVariableAction",
|
|
1780
|
+
name: "Create GitLab Project Variable",
|
|
1570
1781
|
input: {
|
|
1571
1782
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1783
|
+
projectId: "789",
|
|
1784
|
+
key: "DB_PASSWORD",
|
|
1785
|
+
value: "password123",
|
|
1786
|
+
variableType: "env_var",
|
|
1787
|
+
masked: true
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
]
|
|
1791
|
+
})
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
description: "Create a GitLab project variable that is expandable.",
|
|
1795
|
+
example: yaml__default.default.stringify({
|
|
1796
|
+
steps: [
|
|
1797
|
+
{
|
|
1798
|
+
id: "createVariable",
|
|
1799
|
+
action: "gitlab:projectVariable:create",
|
|
1800
|
+
name: "Create GitLab Project Variable",
|
|
1801
|
+
input: {
|
|
1802
|
+
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1803
|
+
projectId: "123",
|
|
1804
|
+
key: "MY_VARIABLE",
|
|
1805
|
+
value: "my_value",
|
|
1806
|
+
variableType: "env_var",
|
|
1807
|
+
raw: true
|
|
1577
1808
|
}
|
|
1578
1809
|
}
|
|
1579
1810
|
]
|
|
1580
1811
|
})
|
|
1581
1812
|
},
|
|
1582
1813
|
{
|
|
1583
|
-
description: "Create a
|
|
1814
|
+
description: "Create a GitLab project variable with a specific environment scope.",
|
|
1584
1815
|
example: yaml__default.default.stringify({
|
|
1585
1816
|
steps: [
|
|
1586
1817
|
{
|
|
1587
|
-
id: "
|
|
1588
|
-
action: "
|
|
1589
|
-
name: "Create
|
|
1818
|
+
id: "createVariable",
|
|
1819
|
+
action: "gitlab:projectVariable:create",
|
|
1820
|
+
name: "Create GitLab Project Variable",
|
|
1590
1821
|
input: {
|
|
1591
1822
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1823
|
+
projectId: "123",
|
|
1824
|
+
key: "MY_VARIABLE",
|
|
1825
|
+
value: "my_value",
|
|
1826
|
+
variableType: "env_var",
|
|
1827
|
+
environmentScope: "production"
|
|
1597
1828
|
}
|
|
1598
1829
|
}
|
|
1599
1830
|
]
|
|
1600
1831
|
})
|
|
1601
1832
|
},
|
|
1602
1833
|
{
|
|
1603
|
-
description: "Create a
|
|
1834
|
+
description: "Create a GitLab project variable with a wildcard environment scope.",
|
|
1604
1835
|
example: yaml__default.default.stringify({
|
|
1605
1836
|
steps: [
|
|
1606
1837
|
{
|
|
1607
|
-
id: "
|
|
1608
|
-
action: "
|
|
1609
|
-
name: "Create
|
|
1838
|
+
id: "createVariable",
|
|
1839
|
+
action: "gitlab:projectVariable:create",
|
|
1840
|
+
name: "Create GitLab Project Variable",
|
|
1610
1841
|
input: {
|
|
1611
1842
|
repoUrl: "gitlab.com?repo=repo&owner=owner",
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1843
|
+
projectId: "123",
|
|
1844
|
+
key: "MY_VARIABLE",
|
|
1845
|
+
value: "my_value",
|
|
1846
|
+
variableType: "env_var",
|
|
1847
|
+
environmentScope: "*"
|
|
1617
1848
|
}
|
|
1618
1849
|
}
|
|
1619
1850
|
]
|
|
@@ -1621,196 +1852,56 @@ const examples$1 = [
|
|
|
1621
1852
|
}
|
|
1622
1853
|
];
|
|
1623
1854
|
|
|
1624
|
-
const
|
|
1855
|
+
const createGitlabProjectVariableAction = (options) => {
|
|
1625
1856
|
const { integrations } = options;
|
|
1626
1857
|
return pluginScaffolderNode.createTemplateAction({
|
|
1627
|
-
id: "
|
|
1858
|
+
id: "gitlab:projectVariable:create",
|
|
1628
1859
|
examples: examples$1,
|
|
1629
1860
|
schema: {
|
|
1630
|
-
input:
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
},
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
},
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
description: "The name for the merge request"
|
|
1649
|
-
},
|
|
1650
|
-
description: {
|
|
1651
|
-
type: "string",
|
|
1652
|
-
title: "Merge Request Description",
|
|
1653
|
-
description: "The description of the merge request"
|
|
1654
|
-
},
|
|
1655
|
-
branchName: {
|
|
1656
|
-
type: "string",
|
|
1657
|
-
title: "Source Branch Name",
|
|
1658
|
-
description: "The source branch name of the merge request"
|
|
1659
|
-
},
|
|
1660
|
-
targetBranchName: {
|
|
1661
|
-
type: "string",
|
|
1662
|
-
title: "Target Branch Name",
|
|
1663
|
-
description: "The target branch name of the merge request"
|
|
1664
|
-
},
|
|
1665
|
-
sourcePath: {
|
|
1666
|
-
type: "string",
|
|
1667
|
-
title: "Working Subdirectory",
|
|
1668
|
-
description: "Subdirectory of working directory to copy changes from"
|
|
1669
|
-
},
|
|
1670
|
-
targetPath: {
|
|
1671
|
-
type: "string",
|
|
1672
|
-
title: "Repository Subdirectory",
|
|
1673
|
-
description: "Subdirectory of repository to apply changes to"
|
|
1674
|
-
},
|
|
1675
|
-
token: {
|
|
1676
|
-
title: "Authentication Token",
|
|
1677
|
-
type: "string",
|
|
1678
|
-
description: "The token to use for authorization to GitLab"
|
|
1679
|
-
},
|
|
1680
|
-
commitAction: {
|
|
1681
|
-
title: "Commit action",
|
|
1682
|
-
type: "string",
|
|
1683
|
-
enum: ["create", "update", "delete"],
|
|
1684
|
-
description: "The action to be used for git commit. Defaults to create."
|
|
1685
|
-
},
|
|
1686
|
-
removeSourceBranch: {
|
|
1687
|
-
title: "Delete source branch",
|
|
1688
|
-
type: "boolean",
|
|
1689
|
-
description: "Option to delete source branch once the MR has been merged. Default: false"
|
|
1690
|
-
},
|
|
1691
|
-
assignee: {
|
|
1692
|
-
title: "Merge Request Assignee",
|
|
1693
|
-
type: "string",
|
|
1694
|
-
description: "User this merge request will be assigned to"
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
},
|
|
1698
|
-
output: {
|
|
1699
|
-
type: "object",
|
|
1700
|
-
properties: {
|
|
1701
|
-
targetBranchName: {
|
|
1702
|
-
title: "Target branch name of the merge request",
|
|
1703
|
-
type: "string"
|
|
1704
|
-
},
|
|
1705
|
-
projectid: {
|
|
1706
|
-
title: "Gitlab Project id/Name(slug)",
|
|
1707
|
-
type: "string"
|
|
1708
|
-
},
|
|
1709
|
-
projectPath: {
|
|
1710
|
-
title: "Gitlab Project path",
|
|
1711
|
-
type: "string"
|
|
1712
|
-
},
|
|
1713
|
-
mergeRequestUrl: {
|
|
1714
|
-
title: "MergeRequest(MR) URL",
|
|
1715
|
-
type: "string",
|
|
1716
|
-
description: "Link to the merge request in GitLab"
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1861
|
+
input: commonGitlabConfig.merge(
|
|
1862
|
+
zod.z.object({
|
|
1863
|
+
projectId: zod.z.union([zod.z.number(), zod.z.string()], {
|
|
1864
|
+
description: "Project ID"
|
|
1865
|
+
}),
|
|
1866
|
+
key: zod.z.string({
|
|
1867
|
+
description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed"
|
|
1868
|
+
}).regex(/^[A-Za-z0-9_]{1,255}$/),
|
|
1869
|
+
value: zod.z.string({ description: "The value of a variable" }),
|
|
1870
|
+
variableType: zod.z.string({
|
|
1871
|
+
description: "Variable Type (env_var or file)"
|
|
1872
|
+
}),
|
|
1873
|
+
variableProtected: zod.z.boolean({ description: "Whether the variable is protected" }).default(false).optional(),
|
|
1874
|
+
masked: zod.z.boolean({ description: "Whether the variable is masked" }).default(false).optional(),
|
|
1875
|
+
raw: zod.z.boolean({ description: "Whether the variable is expandable" }).default(false).optional(),
|
|
1876
|
+
environmentScope: zod.z.string({ description: "The environment_scope of the variable" }).default("*").optional()
|
|
1877
|
+
})
|
|
1878
|
+
)
|
|
1720
1879
|
},
|
|
1721
1880
|
async handler(ctx) {
|
|
1722
1881
|
const {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
title,
|
|
1732
|
-
token
|
|
1882
|
+
projectId,
|
|
1883
|
+
key,
|
|
1884
|
+
value,
|
|
1885
|
+
variableType,
|
|
1886
|
+
variableProtected = false,
|
|
1887
|
+
masked = false,
|
|
1888
|
+
raw = false,
|
|
1889
|
+
environmentScope = "*"
|
|
1733
1890
|
} = ctx.input;
|
|
1734
|
-
const {
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
token,
|
|
1739
|
-
repoUrl
|
|
1740
|
-
});
|
|
1741
|
-
let assigneeId = void 0;
|
|
1742
|
-
if (assignee !== void 0) {
|
|
1743
|
-
try {
|
|
1744
|
-
const assigneeUser = await api.Users.username(assignee);
|
|
1745
|
-
assigneeId = assigneeUser[0].id;
|
|
1746
|
-
} catch (e) {
|
|
1747
|
-
ctx.logger.warn(
|
|
1748
|
-
`Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`
|
|
1749
|
-
);
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
let fileRoot;
|
|
1753
|
-
if (sourcePath) {
|
|
1754
|
-
fileRoot = backendPluginApi.resolveSafeChildPath(ctx.workspacePath, sourcePath);
|
|
1755
|
-
} else if (targetPath) {
|
|
1756
|
-
fileRoot = backendPluginApi.resolveSafeChildPath(ctx.workspacePath, targetPath);
|
|
1757
|
-
} else {
|
|
1758
|
-
fileRoot = ctx.workspacePath;
|
|
1759
|
-
}
|
|
1760
|
-
const fileContents = await pluginScaffolderNode.serializeDirectoryContents(fileRoot, {
|
|
1761
|
-
gitignore: true
|
|
1891
|
+
const { token, integrationConfig } = getToken(ctx.input, integrations);
|
|
1892
|
+
const api = new node.Gitlab({
|
|
1893
|
+
host: integrationConfig.config.baseUrl,
|
|
1894
|
+
token
|
|
1762
1895
|
});
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
};
|
|
1896
|
+
await api.ProjectVariables.create(projectId, {
|
|
1897
|
+
key,
|
|
1898
|
+
value,
|
|
1899
|
+
variable_type: variableType,
|
|
1900
|
+
protected: variableProtected,
|
|
1901
|
+
masked,
|
|
1902
|
+
raw,
|
|
1903
|
+
environment_scope: environmentScope
|
|
1772
1904
|
});
|
|
1773
|
-
let targetBranch = targetBranchName;
|
|
1774
|
-
if (!targetBranch) {
|
|
1775
|
-
const projects = await api.Projects.show(repoID);
|
|
1776
|
-
const { default_branch: defaultBranch } = projects;
|
|
1777
|
-
targetBranch = defaultBranch;
|
|
1778
|
-
}
|
|
1779
|
-
try {
|
|
1780
|
-
await api.Branches.create(repoID, branchName, String(targetBranch));
|
|
1781
|
-
} catch (e) {
|
|
1782
|
-
throw new errors.InputError(
|
|
1783
|
-
`The branch creation failed. Please check that your repo does not already contain a branch named '${branchName}'. ${e}`
|
|
1784
|
-
);
|
|
1785
|
-
}
|
|
1786
|
-
try {
|
|
1787
|
-
await api.Commits.create(repoID, branchName, ctx.input.title, actions);
|
|
1788
|
-
} catch (e) {
|
|
1789
|
-
throw new errors.InputError(
|
|
1790
|
-
`Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${e}`
|
|
1791
|
-
);
|
|
1792
|
-
}
|
|
1793
|
-
try {
|
|
1794
|
-
const mergeRequestUrl = await api.MergeRequests.create(
|
|
1795
|
-
repoID,
|
|
1796
|
-
branchName,
|
|
1797
|
-
String(targetBranch),
|
|
1798
|
-
title,
|
|
1799
|
-
{
|
|
1800
|
-
description,
|
|
1801
|
-
removeSourceBranch: removeSourceBranch ? removeSourceBranch : false,
|
|
1802
|
-
assigneeId
|
|
1803
|
-
}
|
|
1804
|
-
).then((mergeRequest) => {
|
|
1805
|
-
return mergeRequest.web_url;
|
|
1806
|
-
});
|
|
1807
|
-
ctx.output("projectid", repoID);
|
|
1808
|
-
ctx.output("targetBranchName", targetBranch);
|
|
1809
|
-
ctx.output("projectPath", repoID);
|
|
1810
|
-
ctx.output("mergeRequestUrl", mergeRequestUrl);
|
|
1811
|
-
} catch (e) {
|
|
1812
|
-
throw new errors.InputError(`Merge request creation failed${e}`);
|
|
1813
|
-
}
|
|
1814
1905
|
}
|
|
1815
1906
|
});
|
|
1816
1907
|
};
|
|
@@ -1939,7 +2030,6 @@ const createGitlabRepoPushAction = (options) => {
|
|
|
1939
2030
|
}
|
|
1940
2031
|
},
|
|
1941
2032
|
async handler(ctx) {
|
|
1942
|
-
var _a;
|
|
1943
2033
|
const {
|
|
1944
2034
|
branchName,
|
|
1945
2035
|
repoUrl,
|
|
@@ -1965,7 +2055,7 @@ const createGitlabRepoPushAction = (options) => {
|
|
|
1965
2055
|
gitignore: true
|
|
1966
2056
|
});
|
|
1967
2057
|
const actions = fileContents.map((file) => ({
|
|
1968
|
-
action: commitAction
|
|
2058
|
+
action: commitAction ?? "create",
|
|
1969
2059
|
filePath: targetPath ? path__default.default.posix.join(targetPath, file.path) : file.path,
|
|
1970
2060
|
encoding: "base64",
|
|
1971
2061
|
content: file.content.toString("base64"),
|
|
@@ -1976,7 +2066,7 @@ const createGitlabRepoPushAction = (options) => {
|
|
|
1976
2066
|
await api.Branches.show(repoID, branchName);
|
|
1977
2067
|
branchExists = true;
|
|
1978
2068
|
} catch (e) {
|
|
1979
|
-
if (
|
|
2069
|
+
if (e.response?.statusCode !== 404) {
|
|
1980
2070
|
throw new errors.InputError(
|
|
1981
2071
|
`Failed to check status of branch '${branchName}'. Please make sure that branch already exists or Backstage has permissions to create one. ${e}`
|
|
1982
2072
|
);
|
|
@@ -2031,7 +2121,8 @@ const gitlabModule = backendPluginApi.createBackendModule({
|
|
|
2031
2121
|
createGitlabProjectVariableAction({ integrations }),
|
|
2032
2122
|
createGitlabRepoPushAction({ integrations }),
|
|
2033
2123
|
createPublishGitlabAction({ config, integrations }),
|
|
2034
|
-
createPublishGitlabMergeRequestAction({ integrations })
|
|
2124
|
+
createPublishGitlabMergeRequestAction({ integrations }),
|
|
2125
|
+
createTriggerGitlabPipelineAction({ integrations })
|
|
2035
2126
|
);
|
|
2036
2127
|
}
|
|
2037
2128
|
});
|
|
@@ -2047,5 +2138,6 @@ exports.createGitlabProjectVariableAction = createGitlabProjectVariableAction;
|
|
|
2047
2138
|
exports.createGitlabRepoPushAction = createGitlabRepoPushAction;
|
|
2048
2139
|
exports.createPublishGitlabAction = createPublishGitlabAction;
|
|
2049
2140
|
exports.createPublishGitlabMergeRequestAction = createPublishGitlabMergeRequestAction;
|
|
2141
|
+
exports.createTriggerGitlabPipelineAction = createTriggerGitlabPipelineAction;
|
|
2050
2142
|
exports.default = gitlabModule;
|
|
2051
2143
|
//# sourceMappingURL=index.cjs.js.map
|