@stackgenhq/backstage-plugin-stackgen-backend 0.3.6-beta.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/README.md +485 -0
- package/config.d.ts +39 -0
- package/dist/actions/core/assign_project_members_action.cjs.js +227 -0
- package/dist/actions/core/assign_project_members_action.cjs.js.map +1 -0
- package/dist/actions/core/create_appstack_action.cjs.js +953 -0
- package/dist/actions/core/create_appstack_action.cjs.js.map +1 -0
- package/dist/actions/core/create_project_action.cjs.js +243 -0
- package/dist/actions/core/create_project_action.cjs.js.map +1 -0
- package/dist/actions/core/download_iac_action.cjs.js +133 -0
- package/dist/actions/core/download_iac_action.cjs.js.map +1 -0
- package/dist/actions/core/set_environment_variable_values_action.cjs.js +121 -0
- package/dist/actions/core/set_environment_variable_values_action.cjs.js.map +1 -0
- package/dist/actions/core/set_state_backend_action.cjs.js +174 -0
- package/dist/actions/core/set_state_backend_action.cjs.js.map +1 -0
- package/dist/actions/exporter/export_iac_to_git_action.cjs.js +290 -0
- package/dist/actions/exporter/export_iac_to_git_action.cjs.js.map +1 -0
- package/dist/actions/exporter/list_vault_secrets_action.cjs.js +39 -0
- package/dist/actions/exporter/list_vault_secrets_action.cjs.js.map +1 -0
- package/dist/config/constants.cjs.js +23 -0
- package/dist/config/constants.cjs.js.map +1 -0
- package/dist/exporter/exportOverrides.cjs.js +27 -0
- package/dist/exporter/exportOverrides.cjs.js.map +1 -0
- package/dist/exporter/gitExporterConfigHttp.cjs.js +105 -0
- package/dist/exporter/gitExporterConfigHttp.cjs.js.map +1 -0
- package/dist/exporter/http.cjs.js +14 -0
- package/dist/exporter/http.cjs.js.map +1 -0
- package/dist/exporter/paths.cjs.js +25 -0
- package/dist/exporter/paths.cjs.js.map +1 -0
- package/dist/exporter/projectGitExporterTemplate.cjs.js +62 -0
- package/dist/exporter/projectGitExporterTemplate.cjs.js.map +1 -0
- package/dist/exporter/topologyResolve.cjs.js +71 -0
- package/dist/exporter/topologyResolve.cjs.js.map +1 -0
- package/dist/index.cjs.js +31 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +224 -0
- package/dist/lib/extractArchive.cjs.js +62 -0
- package/dist/lib/extractArchive.cjs.js.map +1 -0
- package/dist/modules/stackgenExporterScaffolderModule.cjs.js +29 -0
- package/dist/modules/stackgenExporterScaffolderModule.cjs.js.map +1 -0
- package/dist/modules/stackgenUiProxiesModule.cjs.js +366 -0
- package/dist/modules/stackgenUiProxiesModule.cjs.js.map +1 -0
- package/dist/plugin/plugin.cjs.js +136 -0
- package/dist/plugin/plugin.cjs.js.map +1 -0
- package/dist/plugin/router.cjs.js +341 -0
- package/dist/plugin/router.cjs.js.map +1 -0
- package/dist/services/MappingsService/mappingsService.cjs.js +149 -0
- package/dist/services/MappingsService/mappingsService.cjs.js.map +1 -0
- package/dist/services/StackgenService/stackgenService.cjs.js +267 -0
- package/dist/services/StackgenService/stackgenService.cjs.js.map +1 -0
- package/dist/utils/api-objects.cjs.js +205 -0
- package/dist/utils/api-objects.cjs.js.map +1 -0
- package/dist/vendor/stackgen-api-client/index.cjs.js +47681 -0
- package/dist/vendor/stackgen-api-client/index.cjs.js.map +1 -0
- package/migrations/20250131055302_init.js +24 -0
- package/migrations/20250305123456_alter_type_associations.js +23 -0
- package/package.json +86 -0
- package/templates/appstack-configure-environment.yaml +81 -0
- package/templates/appstack-from-template.yaml +76 -0
- package/templates/appstack-with-modules.yaml +69 -0
- package/templates/appstack-with-resources.yaml +81 -0
- package/templates/export-iac.yaml +97 -0
- package/templates/full-infra-setup.yaml +156 -0
- package/templates/git_export_exporter_multi_scm.yaml +123 -0
- package/templates/project-advanced.yaml +77 -0
- package/templates/project-basic.yaml +39 -0
- package/templates/project-with-members.yaml +86 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
|
|
4
|
+
var zod = require('zod');
|
|
5
|
+
var apiObjects = require('../../utils/api-objects.cjs.js');
|
|
6
|
+
|
|
7
|
+
const memberSchema = zod.z.object({
|
|
8
|
+
type: zod.z.enum(["user", "group"]),
|
|
9
|
+
id: zod.z.string().min(1),
|
|
10
|
+
label: zod.z.string().optional()
|
|
11
|
+
});
|
|
12
|
+
const assignProjectMembersInputSchema = zod.z.object({
|
|
13
|
+
/** StackGen project / team (org) id. */
|
|
14
|
+
projectId: zod.z.string().min(1, "projectId is required"),
|
|
15
|
+
/** Output of the UserGroupSelect scaffolder field. */
|
|
16
|
+
members: zod.z.array(memberSchema).default([]),
|
|
17
|
+
/** Role UUID for assigned users/groups. When omitted, resolves project developer role. */
|
|
18
|
+
roleId: zod.z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
const assignProjectMembersOutputSchema = zod.z.object({
|
|
21
|
+
assignedUsers: zod.z.number(),
|
|
22
|
+
assignedGroups: zod.z.number(),
|
|
23
|
+
/** Newline-separated labels for scaffolder output.text tabs. */
|
|
24
|
+
assignedUsersText: zod.z.string(),
|
|
25
|
+
assignedGroupsText: zod.z.string(),
|
|
26
|
+
roleId: zod.z.string().optional()
|
|
27
|
+
});
|
|
28
|
+
async function resolveProjectMemberRoleId(stackgenApis, preferredRoleId, logger) {
|
|
29
|
+
if (preferredRoleId?.trim()) {
|
|
30
|
+
return preferredRoleId.trim();
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const response = await stackgenApis.roleApiObj.listRoles();
|
|
34
|
+
const roles = response?.roles ?? [];
|
|
35
|
+
const byName = (name) => roles.find((role) => role.name?.toLowerCase() === name)?.id?.trim();
|
|
36
|
+
const resolved = byName("developer") || byName("admin") || roles[0]?.id?.trim();
|
|
37
|
+
if (resolved) {
|
|
38
|
+
logger.info(`Resolved project member roleId=${resolved}`);
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const detail = await apiObjects.formatClientErrorMessage(error);
|
|
43
|
+
logger.warn(`Failed to list roles for member assignment: ${detail}`);
|
|
44
|
+
}
|
|
45
|
+
throw new Error(
|
|
46
|
+
"Could not resolve a project member roleId. Set stackGen.projectMemberRoleId or ensure RoleManagementApi.listRoles returns roles."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
function readUserId(row) {
|
|
50
|
+
return String(row?.id || row?.userId || row?.user?.id || "").trim();
|
|
51
|
+
}
|
|
52
|
+
function readGroupId(row) {
|
|
53
|
+
return String(row?.groupId || row?.id || row?.group?.id || "").trim();
|
|
54
|
+
}
|
|
55
|
+
function isAlreadyMemberError(status, text) {
|
|
56
|
+
const lowered = text.toLowerCase();
|
|
57
|
+
return status === 409 || lowered.includes("already member") || lowered.includes("already exists") || lowered.includes("already assigned");
|
|
58
|
+
}
|
|
59
|
+
async function loadProjectMembership(stackgenApis, projectId) {
|
|
60
|
+
const orgUsers = await stackgenApis.projectApiObject.getOrganizationUsers({
|
|
61
|
+
orgId: projectId
|
|
62
|
+
});
|
|
63
|
+
const orgGroups = await stackgenApis.projectApiObject.getOrganizationGroups({
|
|
64
|
+
orgId: projectId
|
|
65
|
+
});
|
|
66
|
+
const userRows = Array.isArray(orgUsers) ? orgUsers : [];
|
|
67
|
+
let groupRows;
|
|
68
|
+
if (Array.isArray(orgGroups?.groupAssignments)) {
|
|
69
|
+
groupRows = orgGroups.groupAssignments;
|
|
70
|
+
} else if (Array.isArray(orgGroups)) {
|
|
71
|
+
groupRows = orgGroups;
|
|
72
|
+
} else {
|
|
73
|
+
groupRows = [];
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
userIds: new Set(userRows.map(readUserId).filter(Boolean)),
|
|
77
|
+
groupIds: new Set(groupRows.map(readGroupId).filter(Boolean))
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const assignProjectMembersAction = (config, logger) => {
|
|
81
|
+
return pluginScaffolderNode.createTemplateAction({
|
|
82
|
+
id: "stackGen:assignProjectMembers",
|
|
83
|
+
description: "Assigns StackGen users and/or groups to a project (from UserGroupSelect)",
|
|
84
|
+
schema: {
|
|
85
|
+
input: () => assignProjectMembersInputSchema,
|
|
86
|
+
output: () => assignProjectMembersOutputSchema
|
|
87
|
+
},
|
|
88
|
+
async handler(ctx) {
|
|
89
|
+
const stackgenApis = apiObjects.getStackgenApiObjects(config);
|
|
90
|
+
const projectId = ctx.input.projectId.trim();
|
|
91
|
+
const members = ctx.input.members ?? [];
|
|
92
|
+
const users = members.filter((member) => member.type === "user");
|
|
93
|
+
const groups = members.filter((member) => member.type === "group");
|
|
94
|
+
const formatMemberLines = (list, emptyLabel) => list.length === 0 ? emptyLabel : list.map((member) => member.label?.trim() || member.id).join("\n");
|
|
95
|
+
if (users.length === 0 && groups.length === 0) {
|
|
96
|
+
ctx.logger.info("No members selected; skipping assignment");
|
|
97
|
+
ctx.output("assignedUsers", 0);
|
|
98
|
+
ctx.output("assignedGroups", 0);
|
|
99
|
+
ctx.output("assignedUsersText", "No users assigned");
|
|
100
|
+
ctx.output("assignedGroupsText", "No groups assigned");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const roleId = await resolveProjectMemberRoleId(
|
|
104
|
+
stackgenApis,
|
|
105
|
+
ctx.input.roleId?.trim() || config.getOptionalString("stackGen.projectMemberRoleId")?.trim(),
|
|
106
|
+
logger
|
|
107
|
+
);
|
|
108
|
+
let existing = await loadProjectMembership(stackgenApis, projectId);
|
|
109
|
+
ctx.logger.info(
|
|
110
|
+
`Project ${projectId} currently has ${existing.userIds.size} user(s) and ${existing.groupIds.size} group(s)`
|
|
111
|
+
);
|
|
112
|
+
const usersToAdd = users.filter((user) => !existing.userIds.has(user.id));
|
|
113
|
+
const groupsToAdd = groups.filter(
|
|
114
|
+
(group) => !existing.groupIds.has(group.id)
|
|
115
|
+
);
|
|
116
|
+
const skippedUsers = users.filter((user) => existing.userIds.has(user.id));
|
|
117
|
+
const skippedGroups = groups.filter(
|
|
118
|
+
(group) => existing.groupIds.has(group.id)
|
|
119
|
+
);
|
|
120
|
+
if (skippedUsers.length > 0) {
|
|
121
|
+
ctx.logger.info(
|
|
122
|
+
`Skipping ${skippedUsers.length} already-present user(s): ${skippedUsers.map((user) => user.label || user.id).join(", ")}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (skippedGroups.length > 0) {
|
|
126
|
+
ctx.logger.info(
|
|
127
|
+
`Skipping ${skippedGroups.length} already-present group(s): ${skippedGroups.map((group) => group.label || group.id).join(", ")}`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
for (const user of usersToAdd) {
|
|
131
|
+
ctx.logger.info(
|
|
132
|
+
`Assigning user ${user.label || user.id} to project ${projectId} with role ${roleId}`
|
|
133
|
+
);
|
|
134
|
+
try {
|
|
135
|
+
await stackgenApis.projectApiObject.assignUsersToOrg({
|
|
136
|
+
orgId: projectId,
|
|
137
|
+
assignUsersToOrgRequest: {
|
|
138
|
+
userAssignments: [{ userId: user.id, roleId }]
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const parsedError = await apiObjects.readClientError(error);
|
|
143
|
+
const detail = apiObjects.formatApiFailure(
|
|
144
|
+
parsedError.status,
|
|
145
|
+
parsedError.body,
|
|
146
|
+
parsedError.text,
|
|
147
|
+
parsedError.requestId
|
|
148
|
+
);
|
|
149
|
+
if (!isAlreadyMemberError(parsedError.status, detail) && !isAlreadyMemberError(parsedError.status, parsedError.text)) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Failed to assign user ${user.label || user.id} to project: ${detail}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
ctx.logger.info(
|
|
155
|
+
`User ${user.label || user.id} was already a project member`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (groupsToAdd.length > 0) {
|
|
160
|
+
ctx.logger.info(
|
|
161
|
+
`Assigning ${groupsToAdd.length} group(s) to project ${projectId} with role ${roleId}`
|
|
162
|
+
);
|
|
163
|
+
try {
|
|
164
|
+
await stackgenApis.projectApiObject.assignGroupsToOrg({
|
|
165
|
+
orgId: projectId,
|
|
166
|
+
assignGroupsToOrgRequest: {
|
|
167
|
+
groupAssignments: groupsToAdd.map((group) => ({
|
|
168
|
+
groupId: group.id,
|
|
169
|
+
roleId
|
|
170
|
+
}))
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
const parsedError = await apiObjects.readClientError(error);
|
|
175
|
+
const detail = apiObjects.formatApiFailure(
|
|
176
|
+
parsedError.status,
|
|
177
|
+
parsedError.body,
|
|
178
|
+
parsedError.text,
|
|
179
|
+
parsedError.requestId
|
|
180
|
+
);
|
|
181
|
+
if (!isAlreadyMemberError(parsedError.status, detail) && !isAlreadyMemberError(parsedError.status, parsedError.text)) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Failed to assign groups to project: ${detail}`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
ctx.logger.info("Some groups were already project members");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
existing = await loadProjectMembership(stackgenApis, projectId);
|
|
190
|
+
ctx.logger.info(
|
|
191
|
+
`Project ${projectId} now has ${existing.userIds.size} user(s) and ${existing.groupIds.size} group(s)`
|
|
192
|
+
);
|
|
193
|
+
const missingUsers = users.filter(
|
|
194
|
+
(user) => !existing.userIds.has(user.id)
|
|
195
|
+
);
|
|
196
|
+
if (missingUsers.length > 0) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Assigned users but ${missingUsers.length} are still missing from project members: ${missingUsers.map((user) => user.label || user.id).join(", ")}. Check roleId and project id.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const missingGroups = groups.filter(
|
|
202
|
+
(group) => !existing.groupIds.has(group.id)
|
|
203
|
+
);
|
|
204
|
+
if (missingGroups.length > 0) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
`Assigned groups but ${missingGroups.length} are still missing from project members: ${missingGroups.map((group) => group.label || group.id).join(", ")}. Check roleId and project id.`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
ctx.output("assignedUsers", users.length);
|
|
210
|
+
ctx.output("assignedGroups", groups.length);
|
|
211
|
+
ctx.output(
|
|
212
|
+
"assignedUsersText",
|
|
213
|
+
formatMemberLines(users, "No users assigned")
|
|
214
|
+
);
|
|
215
|
+
ctx.output(
|
|
216
|
+
"assignedGroupsText",
|
|
217
|
+
formatMemberLines(groups, "No groups assigned")
|
|
218
|
+
);
|
|
219
|
+
ctx.output("roleId", roleId);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
exports.assignProjectMembersAction = assignProjectMembersAction;
|
|
225
|
+
exports.assignProjectMembersInputSchema = assignProjectMembersInputSchema;
|
|
226
|
+
exports.assignProjectMembersOutputSchema = assignProjectMembersOutputSchema;
|
|
227
|
+
//# sourceMappingURL=assign_project_members_action.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assign_project_members_action.cjs.js","sources":["../../../src/actions/core/assign_project_members_action.ts"],"sourcesContent":["import { createTemplateAction } from \"@backstage/plugin-scaffolder-node\";\nimport { LoggerService } from \"@backstage/backend-plugin-api\";\nimport { Config } from \"@backstage/config\";\nimport { z } from \"zod\";\nimport {\n formatApiFailure,\n formatClientErrorMessage,\n getStackgenApiObjects,\n readClientError,\n} from \"../../utils/api-objects\";\n\nconst memberSchema = z.object({\n type: z.enum([\"user\", \"group\"]),\n id: z.string().min(1),\n label: z.string().optional(),\n});\n\nexport const assignProjectMembersInputSchema = z.object({\n /** StackGen project / team (org) id. */\n projectId: z.string().min(1, \"projectId is required\"),\n /** Output of the UserGroupSelect scaffolder field. */\n members: z.array(memberSchema).default([]),\n /** Role UUID for assigned users/groups. When omitted, resolves project developer role. */\n roleId: z.string().optional(),\n});\n\nexport const assignProjectMembersOutputSchema = z.object({\n assignedUsers: z.number(),\n assignedGroups: z.number(),\n /** Newline-separated labels for scaffolder output.text tabs. */\n assignedUsersText: z.string(),\n assignedGroupsText: z.string(),\n roleId: z.string().optional(),\n});\n\nasync function resolveProjectMemberRoleId(\n stackgenApis: ReturnType<typeof getStackgenApiObjects>,\n preferredRoleId: string | undefined,\n logger: LoggerService,\n): Promise<string> {\n if (preferredRoleId?.trim()) {\n return preferredRoleId.trim();\n }\n\n try {\n const response = await stackgenApis.roleApiObj.listRoles();\n const roles = response?.roles ?? [];\n const byName = (name: string) =>\n roles.find((role) => role.name?.toLowerCase() === name)?.id?.trim();\n\n // Match appcd-ui project member defaults: developer, then admin, then first role.\n const resolved =\n byName(\"developer\") || byName(\"admin\") || roles[0]?.id?.trim();\n if (resolved) {\n logger.info(`Resolved project member roleId=${resolved}`);\n return resolved;\n }\n } catch (error) {\n const detail = await formatClientErrorMessage(error);\n logger.warn(`Failed to list roles for member assignment: ${detail}`);\n }\n\n throw new Error(\n \"Could not resolve a project member roleId. Set stackGen.projectMemberRoleId or ensure RoleManagementApi.listRoles returns roles.\",\n );\n}\n\nfunction readUserId(row: any): string {\n return String(row?.id || row?.userId || row?.user?.id || \"\").trim();\n}\n\nfunction readGroupId(row: any): string {\n return String(row?.groupId || row?.id || row?.group?.id || \"\").trim();\n}\n\nfunction isAlreadyMemberError(status: number, text: string): boolean {\n const lowered = text.toLowerCase();\n return (\n status === 409 ||\n lowered.includes(\"already member\") ||\n lowered.includes(\"already exists\") ||\n lowered.includes(\"already assigned\")\n );\n}\n\nasync function loadProjectMembership(\n stackgenApis: ReturnType<typeof getStackgenApiObjects>,\n projectId: string,\n): Promise<{ userIds: Set<string>; groupIds: Set<string> }> {\n const orgUsers = await stackgenApis.projectApiObject.getOrganizationUsers({\n orgId: projectId,\n });\n const orgGroups = await stackgenApis.projectApiObject.getOrganizationGroups({\n orgId: projectId,\n });\n const userRows = Array.isArray(orgUsers) ? orgUsers : [];\n let groupRows: any[];\n if (Array.isArray(orgGroups?.groupAssignments)) {\n groupRows = orgGroups.groupAssignments;\n } else if (Array.isArray(orgGroups)) {\n groupRows = orgGroups;\n } else {\n groupRows = [];\n }\n\n return {\n userIds: new Set(userRows.map(readUserId).filter(Boolean)),\n groupIds: new Set(groupRows.map(readGroupId).filter(Boolean)),\n };\n}\n\n/**\n * Assigns users and/or groups from UserGroupSelect to a StackGen project.\n * Uses the same OrgManagement APIs as appcd-ui project membership.\n */\nexport const assignProjectMembersAction = (\n config: Config,\n logger: LoggerService,\n) => {\n return createTemplateAction({\n id: \"stackGen:assignProjectMembers\",\n description:\n \"Assigns StackGen users and/or groups to a project (from UserGroupSelect)\",\n schema: {\n input: () => assignProjectMembersInputSchema,\n output: () => assignProjectMembersOutputSchema,\n },\n async handler(ctx) {\n const stackgenApis = getStackgenApiObjects(config);\n const projectId = ctx.input.projectId.trim();\n const members = ctx.input.members ?? [];\n\n const users = members.filter((member) => member.type === \"user\");\n const groups = members.filter((member) => member.type === \"group\");\n const formatMemberLines = (\n list: Array<{ id: string; label?: string }>,\n emptyLabel: string,\n ) =>\n list.length === 0\n ? emptyLabel\n : list\n .map((member) => member.label?.trim() || member.id)\n .join(\"\\n\");\n\n if (users.length === 0 && groups.length === 0) {\n ctx.logger.info(\"No members selected; skipping assignment\");\n ctx.output(\"assignedUsers\", 0);\n ctx.output(\"assignedGroups\", 0);\n ctx.output(\"assignedUsersText\", \"No users assigned\");\n ctx.output(\"assignedGroupsText\", \"No groups assigned\");\n return;\n }\n\n const roleId = await resolveProjectMemberRoleId(\n stackgenApis,\n ctx.input.roleId?.trim() ||\n config.getOptionalString(\"stackGen.projectMemberRoleId\")?.trim(),\n logger,\n );\n\n // Project create / createAppStack often already added the current user.\n // Skip existing members so an \"already member\" response cannot block the rest.\n let existing = await loadProjectMembership(stackgenApis, projectId);\n ctx.logger.info(\n `Project ${projectId} currently has ${existing.userIds.size} user(s) and ${existing.groupIds.size} group(s)`,\n );\n\n const usersToAdd = users.filter((user) => !existing.userIds.has(user.id));\n const groupsToAdd = groups.filter(\n (group) => !existing.groupIds.has(group.id),\n );\n const skippedUsers = users.filter((user) => existing.userIds.has(user.id));\n const skippedGroups = groups.filter((group) =>\n existing.groupIds.has(group.id),\n );\n\n if (skippedUsers.length > 0) {\n ctx.logger.info(\n `Skipping ${skippedUsers.length} already-present user(s): ${skippedUsers\n .map((user) => user.label || user.id)\n .join(\", \")}`,\n );\n }\n if (skippedGroups.length > 0) {\n ctx.logger.info(\n `Skipping ${skippedGroups.length} already-present group(s): ${skippedGroups\n .map((group) => group.label || group.id)\n .join(\", \")}`,\n );\n }\n\n // Assign users one-by-one so one conflict cannot drop the rest of the batch.\n for (const user of usersToAdd) {\n ctx.logger.info(\n `Assigning user ${user.label || user.id} to project ${projectId} with role ${roleId}`,\n );\n try {\n await stackgenApis.projectApiObject.assignUsersToOrg({\n orgId: projectId,\n assignUsersToOrgRequest: {\n userAssignments: [{ userId: user.id, roleId }],\n } as never,\n });\n } catch (error) {\n const parsedError = await readClientError(error);\n const detail = formatApiFailure(\n parsedError.status,\n parsedError.body,\n parsedError.text,\n parsedError.requestId,\n );\n if (\n !isAlreadyMemberError(parsedError.status, detail) &&\n !isAlreadyMemberError(parsedError.status, parsedError.text)\n ) {\n throw new Error(\n `Failed to assign user ${user.label || user.id} to project: ${detail}`,\n );\n }\n ctx.logger.info(\n `User ${user.label || user.id} was already a project member`,\n );\n }\n }\n\n if (groupsToAdd.length > 0) {\n ctx.logger.info(\n `Assigning ${groupsToAdd.length} group(s) to project ${projectId} with role ${roleId}`,\n );\n try {\n await stackgenApis.projectApiObject.assignGroupsToOrg({\n orgId: projectId,\n assignGroupsToOrgRequest: {\n groupAssignments: groupsToAdd.map((group) => ({\n groupId: group.id,\n roleId,\n })),\n },\n });\n } catch (error) {\n const parsedError = await readClientError(error);\n const detail = formatApiFailure(\n parsedError.status,\n parsedError.body,\n parsedError.text,\n parsedError.requestId,\n );\n if (\n !isAlreadyMemberError(parsedError.status, detail) &&\n !isAlreadyMemberError(parsedError.status, parsedError.text)\n ) {\n throw new Error(\n `Failed to assign groups to project: ${detail}`,\n );\n }\n ctx.logger.info(\"Some groups were already project members\");\n }\n }\n\n existing = await loadProjectMembership(stackgenApis, projectId);\n ctx.logger.info(\n `Project ${projectId} now has ${existing.userIds.size} user(s) and ${existing.groupIds.size} group(s)`,\n );\n\n const missingUsers = users.filter(\n (user) => !existing.userIds.has(user.id),\n );\n if (missingUsers.length > 0) {\n throw new Error(\n `Assigned users but ${missingUsers.length} are still missing from project members: ${missingUsers\n .map((user) => user.label || user.id)\n .join(\", \")}. Check roleId and project id.`,\n );\n }\n\n const missingGroups = groups.filter(\n (group) => !existing.groupIds.has(group.id),\n );\n if (missingGroups.length > 0) {\n throw new Error(\n `Assigned groups but ${missingGroups.length} are still missing from project members: ${missingGroups\n .map((group) => group.label || group.id)\n .join(\", \")}. Check roleId and project id.`,\n );\n }\n\n ctx.output(\"assignedUsers\", users.length);\n ctx.output(\"assignedGroups\", groups.length);\n ctx.output(\n \"assignedUsersText\",\n formatMemberLines(users, \"No users assigned\"),\n );\n ctx.output(\n \"assignedGroupsText\",\n formatMemberLines(groups, \"No groups assigned\"),\n );\n ctx.output(\"roleId\", roleId);\n },\n });\n};\n"],"names":["z","formatClientErrorMessage","createTemplateAction","getStackgenApiObjects","readClientError","formatApiFailure"],"mappings":"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"}
|