@tailor-platform/sdk 0.8.6 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/dist/cli/api.d.mts +12 -11
- package/dist/cli/api.mjs +1 -1
- package/dist/cli/index.mjs +4 -5
- package/dist/configure/index.d.mts +2 -2
- package/dist/{index-DHpKRtq3.d.mts → index-DxmBZtRb.d.mts} +15 -2
- package/dist/{token-Cbs_El75.mjs → token-BD9c1mlS.mjs} +709 -274
- package/dist/{types-CPcmGK_X.d.mts → types-DcpYyMM2.d.mts} +4 -3
- package/dist/utils/test/index.d.mts +2 -2
- package/docs/cli-reference.md +1 -0
- package/docs/configuration.md +31 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ import * as os from "node:os";
|
|
|
21
21
|
import { parseTOML, parseYAML, stringifyYAML } from "confbox";
|
|
22
22
|
import { xdgConfig } from "xdg-basedir";
|
|
23
23
|
import { fromJson } from "@bufbuild/protobuf";
|
|
24
|
+
import chalk from "chalk";
|
|
24
25
|
import { spawn } from "node:child_process";
|
|
25
26
|
import { glob } from "node:fs/promises";
|
|
26
27
|
import chokidar from "chokidar";
|
|
@@ -155,7 +156,7 @@ const FunctionOperationSchema = z.object({
|
|
|
155
156
|
});
|
|
156
157
|
const GqlOperationSchema = z.object({
|
|
157
158
|
kind: z.literal("graphql"),
|
|
158
|
-
appName: z.string(),
|
|
159
|
+
appName: z.string().optional(),
|
|
159
160
|
query: z.string(),
|
|
160
161
|
variables: functionSchema.optional(),
|
|
161
162
|
invoker: InvokerSchema.optional()
|
|
@@ -190,6 +191,7 @@ var ExecutorService = class {
|
|
|
190
191
|
this.config = config;
|
|
191
192
|
}
|
|
192
193
|
async loadExecutors() {
|
|
194
|
+
if (Object.keys(this.executors).length > 0) return this.executors;
|
|
193
195
|
if (!this.config.files || this.config.files.length === 0) return;
|
|
194
196
|
const executorFiles = loadFilesWithIgnores(this.config);
|
|
195
197
|
console.log("");
|
|
@@ -275,6 +277,7 @@ var ResolverService = class {
|
|
|
275
277
|
this.config = config;
|
|
276
278
|
}
|
|
277
279
|
async loadResolvers() {
|
|
280
|
+
if (Object.keys(this.resolvers).length > 0) return;
|
|
278
281
|
if (!this.config.files || this.config.files.length === 0) return;
|
|
279
282
|
const resolverFiles = loadFilesWithIgnores(this.config);
|
|
280
283
|
console.log("");
|
|
@@ -464,9 +467,11 @@ var Application = class {
|
|
|
464
467
|
_subgraphs = [];
|
|
465
468
|
_executorService = void 0;
|
|
466
469
|
_staticWebsiteServices = [];
|
|
470
|
+
_env = {};
|
|
467
471
|
constructor(name, config) {
|
|
468
472
|
this.name = name;
|
|
469
473
|
this.config = config;
|
|
474
|
+
this._env = config.env || {};
|
|
470
475
|
}
|
|
471
476
|
addSubgraph(type, name) {
|
|
472
477
|
this._subgraphs.push({
|
|
@@ -495,6 +500,9 @@ var Application = class {
|
|
|
495
500
|
get staticWebsiteServices() {
|
|
496
501
|
return this._staticWebsiteServices;
|
|
497
502
|
}
|
|
503
|
+
get env() {
|
|
504
|
+
return this._env;
|
|
505
|
+
}
|
|
498
506
|
get applications() {
|
|
499
507
|
return [this];
|
|
500
508
|
}
|
|
@@ -1576,13 +1584,20 @@ async function loadConfig(configPath) {
|
|
|
1576
1584
|
function extractAttributesFromConfig(config) {
|
|
1577
1585
|
return collectAttributesFromConfig(config);
|
|
1578
1586
|
}
|
|
1579
|
-
function generateTypeDefinition(attributeMap, attributeList) {
|
|
1587
|
+
function generateTypeDefinition(attributeMap, attributeList, env) {
|
|
1580
1588
|
const mapFields = attributeMap ? Object.entries(attributeMap).map(([key, value]) => ` ${key}: ${value};`).join("\n") : "";
|
|
1581
1589
|
const mapBody = !attributeMap || Object.keys(attributeMap).length === 0 ? "{}" : `{
|
|
1582
1590
|
${mapFields}
|
|
1583
1591
|
}`;
|
|
1584
1592
|
const listBody = `{
|
|
1585
1593
|
__tuple?: ${attributeList ? `[${attributeList.map(() => "string").join(", ")}]` : "[]"};
|
|
1594
|
+
}`;
|
|
1595
|
+
const envFields = env ? Object.entries(env).map(([key, value]) => {
|
|
1596
|
+
const valueType = typeof value === "string" ? `"${value}"` : String(value);
|
|
1597
|
+
return ` ${key}: ${valueType};`;
|
|
1598
|
+
}).join("\n") : "";
|
|
1599
|
+
const envBody = !env || Object.keys(env).length === 0 ? "{}" : `{
|
|
1600
|
+
${envFields}
|
|
1586
1601
|
}`;
|
|
1587
1602
|
return ml`
|
|
1588
1603
|
// This file is auto-generated by @tailor-platform/sdk
|
|
@@ -1593,6 +1608,7 @@ declare global {
|
|
|
1593
1608
|
namespace TailorSDK {
|
|
1594
1609
|
interface AttributeMap ${mapBody}
|
|
1595
1610
|
interface AttributeList ${listBody}
|
|
1611
|
+
interface Env ${envBody}
|
|
1596
1612
|
}
|
|
1597
1613
|
}
|
|
1598
1614
|
|
|
@@ -1637,13 +1653,12 @@ function resolveTypeDefinitionPath(configPath) {
|
|
|
1637
1653
|
async function generateUserTypes(config, configPath) {
|
|
1638
1654
|
try {
|
|
1639
1655
|
const { attributeMap, attributeList } = extractAttributesFromConfig(config);
|
|
1640
|
-
if (!attributeMap && !attributeList)
|
|
1641
|
-
console.log(styleText("cyan", "No attributes found in configuration"));
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1656
|
+
if (!attributeMap && !attributeList) console.log(styleText("cyan", "No attributes found in configuration"));
|
|
1644
1657
|
if (attributeMap) console.log("Extracted AttributeMap:", attributeMap);
|
|
1645
1658
|
if (attributeList) console.log("Extracted AttributeList:", attributeList);
|
|
1646
|
-
const
|
|
1659
|
+
const env = config.env;
|
|
1660
|
+
if (env) console.log("Extracted Env:", env);
|
|
1661
|
+
const typeDefContent = generateTypeDefinition(attributeMap, attributeList, env);
|
|
1647
1662
|
const outputPath = resolveTypeDefinitionPath(configPath);
|
|
1648
1663
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
1649
1664
|
fs.writeFileSync(outputPath, typeDefContent);
|
|
@@ -2254,6 +2269,15 @@ const file_tailor_v1_service = /* @__PURE__ */ fileDesc("Chd0YWlsb3IvdjEvc2Vydml
|
|
|
2254
2269
|
*/
|
|
2255
2270
|
const OperatorService = /* @__PURE__ */ serviceDesc(file_tailor_v1_service, 0);
|
|
2256
2271
|
|
|
2272
|
+
//#endregion
|
|
2273
|
+
//#region src/cli/package-json.ts
|
|
2274
|
+
let packageJson = null;
|
|
2275
|
+
async function readPackageJson() {
|
|
2276
|
+
if (packageJson) return packageJson;
|
|
2277
|
+
packageJson = await readPackageJSON(import.meta.url);
|
|
2278
|
+
return packageJson;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2257
2281
|
//#endregion
|
|
2258
2282
|
//#region src/cli/client.ts
|
|
2259
2283
|
const baseUrl = process.env.PLATFORM_URL ?? "https://api.tailor.tech";
|
|
@@ -2278,7 +2302,7 @@ async function userAgentInterceptor() {
|
|
|
2278
2302
|
};
|
|
2279
2303
|
}
|
|
2280
2304
|
async function userAgent() {
|
|
2281
|
-
return `tailor-sdk/${(await
|
|
2305
|
+
return `tailor-sdk/${(await readPackageJson()).version ?? "unknown"}`;
|
|
2282
2306
|
}
|
|
2283
2307
|
async function bearerTokenInterceptor(accessToken) {
|
|
2284
2308
|
return (next) => async (req) => {
|
|
@@ -2540,6 +2564,24 @@ function loadConfigPath(configPath) {
|
|
|
2540
2564
|
return "tailor.config.ts";
|
|
2541
2565
|
}
|
|
2542
2566
|
|
|
2567
|
+
//#endregion
|
|
2568
|
+
//#region src/cli/apply/services/label.ts
|
|
2569
|
+
function trnPrefix(workspaceId) {
|
|
2570
|
+
return `trn:v1:workspace:${workspaceId}`;
|
|
2571
|
+
}
|
|
2572
|
+
const sdkNameLabelKey = "sdk-name";
|
|
2573
|
+
async function buildMetaRequest(trn$7, appName) {
|
|
2574
|
+
const packageJson$1 = await readPackageJson();
|
|
2575
|
+
const sdkVersion = packageJson$1.version ? `v${packageJson$1.version.replace(/\./g, "-")}` : "unknown";
|
|
2576
|
+
return {
|
|
2577
|
+
trn: trn$7,
|
|
2578
|
+
labels: {
|
|
2579
|
+
[sdkNameLabelKey]: appName,
|
|
2580
|
+
"sdk-version": sdkVersion
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2543
2585
|
//#endregion
|
|
2544
2586
|
//#region src/cli/apply/services/index.ts
|
|
2545
2587
|
var ChangeSet = class {
|
|
@@ -2569,14 +2611,21 @@ var ChangeSet = class {
|
|
|
2569
2611
|
async function applyApplication(client, changeSet, phase = "create-update") {
|
|
2570
2612
|
if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
|
|
2571
2613
|
create.request.cors = await resolveStaticWebsiteUrls(client, create.request.workspaceId, create.request.cors, "CORS");
|
|
2572
|
-
|
|
2614
|
+
await client.createApplication(create.request);
|
|
2615
|
+
await client.setMetadata(create.metaRequest);
|
|
2573
2616
|
}), ...changeSet.updates.map(async (update) => {
|
|
2574
2617
|
update.request.cors = await resolveStaticWebsiteUrls(client, update.request.workspaceId, update.request.cors, "CORS");
|
|
2575
|
-
|
|
2618
|
+
await client.updateApplication(update.request);
|
|
2619
|
+
await client.setMetadata(update.metaRequest);
|
|
2576
2620
|
})]);
|
|
2577
|
-
else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) =>
|
|
2621
|
+
else if (phase === "delete") await Promise.all(changeSet.deletes.map(async (del) => {
|
|
2622
|
+
await client.deleteApplication(del.request);
|
|
2623
|
+
}));
|
|
2578
2624
|
}
|
|
2579
|
-
|
|
2625
|
+
function trn$6(workspaceId, name) {
|
|
2626
|
+
return `trn:v1:workspace:${workspaceId}:application:${name}`;
|
|
2627
|
+
}
|
|
2628
|
+
async function planApplication({ client, workspaceId, application }) {
|
|
2580
2629
|
const changeSet = new ChangeSet("Applications");
|
|
2581
2630
|
const existingApplications = await fetchAll(async (pageToken) => {
|
|
2582
2631
|
try {
|
|
@@ -2590,55 +2639,41 @@ async function planApplication(client, workspaceId, application) {
|
|
|
2590
2639
|
throw error;
|
|
2591
2640
|
}
|
|
2592
2641
|
});
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2642
|
+
let authNamespace;
|
|
2643
|
+
let authIdpConfigName;
|
|
2644
|
+
if (application.authService && application.authService.config) {
|
|
2645
|
+
authNamespace = application.authService.config.name;
|
|
2646
|
+
const idProvider = application.authService.config.idProvider;
|
|
2647
|
+
if (idProvider) authIdpConfigName = idProvider.name;
|
|
2648
|
+
}
|
|
2649
|
+
const metaRequest = await buildMetaRequest(trn$6(workspaceId, application.name), application.name);
|
|
2650
|
+
if (existingApplications.some((app) => app.name === application.name)) changeSet.updates.push({
|
|
2651
|
+
name: application.name,
|
|
2652
|
+
request: {
|
|
2653
|
+
workspaceId,
|
|
2654
|
+
applicationName: application.name,
|
|
2655
|
+
authNamespace,
|
|
2656
|
+
authIdpConfigName,
|
|
2657
|
+
cors: application.config.cors,
|
|
2658
|
+
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
2659
|
+
allowedIpAddresses: application.config.allowedIPAddresses,
|
|
2660
|
+
disableIntrospection: application.config.disableIntrospection
|
|
2661
|
+
},
|
|
2662
|
+
metaRequest
|
|
2596
2663
|
});
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
applicationName: app.name,
|
|
2611
|
-
authNamespace,
|
|
2612
|
-
authIdpConfigName,
|
|
2613
|
-
cors: app.config.cors,
|
|
2614
|
-
subgraphs: app.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
2615
|
-
allowedIpAddresses: app.config.allowedIPAddresses,
|
|
2616
|
-
disableIntrospection: app.config.disableIntrospection
|
|
2617
|
-
}
|
|
2618
|
-
});
|
|
2619
|
-
existingNameSet.delete(app.name);
|
|
2620
|
-
} else changeSet.creates.push({
|
|
2621
|
-
name: app.name,
|
|
2622
|
-
request: {
|
|
2623
|
-
workspaceId,
|
|
2624
|
-
applicationName: app.name,
|
|
2625
|
-
authNamespace,
|
|
2626
|
-
authIdpConfigName,
|
|
2627
|
-
cors: app.config.cors,
|
|
2628
|
-
subgraphs: app.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
2629
|
-
allowedIpAddresses: app.config.allowedIPAddresses,
|
|
2630
|
-
disableIntrospection: app.config.disableIntrospection
|
|
2631
|
-
}
|
|
2632
|
-
});
|
|
2633
|
-
}
|
|
2634
|
-
existingNameSet.forEach((name) => {
|
|
2635
|
-
changeSet.deletes.push({
|
|
2636
|
-
name,
|
|
2637
|
-
request: {
|
|
2638
|
-
workspaceId,
|
|
2639
|
-
applicationName: name
|
|
2640
|
-
}
|
|
2641
|
-
});
|
|
2664
|
+
else changeSet.creates.push({
|
|
2665
|
+
name: application.name,
|
|
2666
|
+
request: {
|
|
2667
|
+
workspaceId,
|
|
2668
|
+
applicationName: application.name,
|
|
2669
|
+
authNamespace,
|
|
2670
|
+
authIdpConfigName,
|
|
2671
|
+
cors: application.config.cors,
|
|
2672
|
+
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
2673
|
+
allowedIpAddresses: application.config.allowedIPAddresses,
|
|
2674
|
+
disableIntrospection: application.config.disableIntrospection
|
|
2675
|
+
},
|
|
2676
|
+
metaRequest
|
|
2642
2677
|
});
|
|
2643
2678
|
changeSet.print();
|
|
2644
2679
|
return changeSet;
|
|
@@ -2674,9 +2709,16 @@ function idpClientVaultName(namespaceName, clientName) {
|
|
|
2674
2709
|
function idpClientSecretName(namespaceName, clientName) {
|
|
2675
2710
|
return `client-secret-${namespaceName}-${clientName}`;
|
|
2676
2711
|
}
|
|
2677
|
-
async function applyIdP(client,
|
|
2712
|
+
async function applyIdP(client, result, phase = "create-update") {
|
|
2713
|
+
const { changeSet } = result;
|
|
2678
2714
|
if (phase === "create-update") {
|
|
2679
|
-
await Promise.all([...changeSet.service.creates.map(
|
|
2715
|
+
await Promise.all([...changeSet.service.creates.map(async (create) => {
|
|
2716
|
+
await client.createIdPService(create.request);
|
|
2717
|
+
await client.setMetadata(create.metaRequest);
|
|
2718
|
+
}), ...changeSet.service.updates.map(async (update) => {
|
|
2719
|
+
await client.updateIdPService(update.request);
|
|
2720
|
+
await client.setMetadata(update.metaRequest);
|
|
2721
|
+
})]);
|
|
2680
2722
|
await Promise.all([...changeSet.client.creates.map(async (create) => {
|
|
2681
2723
|
const resp = await client.createIdPClient(create.request);
|
|
2682
2724
|
const vaultName = idpClientVaultName(create.request.namespaceName, create.request.client?.name || "");
|
|
@@ -2715,7 +2757,7 @@ async function applyIdP(client, changeSet, phase = "create-update") {
|
|
|
2715
2757
|
});
|
|
2716
2758
|
})]);
|
|
2717
2759
|
} else if (phase === "delete") {
|
|
2718
|
-
await Promise.all(changeSet.client.deletes.
|
|
2760
|
+
await Promise.all(changeSet.client.deletes.map(async (del) => {
|
|
2719
2761
|
await client.deleteIdPClient(del.request);
|
|
2720
2762
|
const vaultName = `idp-${del.request.namespaceName}-${del.request.name}`;
|
|
2721
2763
|
await client.deleteSecretManagerVault({
|
|
@@ -2726,22 +2768,32 @@ async function applyIdP(client, changeSet, phase = "create-update") {
|
|
|
2726
2768
|
await Promise.all(changeSet.service.deletes.map((del) => client.deleteIdPService(del.request)));
|
|
2727
2769
|
}
|
|
2728
2770
|
}
|
|
2729
|
-
async function planIdP(client, workspaceId, application) {
|
|
2730
|
-
const idps =
|
|
2731
|
-
|
|
2732
|
-
const serviceChangeSet = await planServices$3(client, workspaceId, idps);
|
|
2771
|
+
async function planIdP({ client, workspaceId, application }) {
|
|
2772
|
+
const idps = application.idpServices;
|
|
2773
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$3(client, workspaceId, application.name, idps);
|
|
2733
2774
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
2734
2775
|
const clientChangeSet = await planClients(client, workspaceId, idps, deletedServices);
|
|
2735
2776
|
serviceChangeSet.print();
|
|
2736
2777
|
clientChangeSet.print();
|
|
2737
2778
|
return {
|
|
2738
|
-
|
|
2739
|
-
|
|
2779
|
+
changeSet: {
|
|
2780
|
+
service: serviceChangeSet,
|
|
2781
|
+
client: clientChangeSet
|
|
2782
|
+
},
|
|
2783
|
+
conflicts,
|
|
2784
|
+
unmanaged,
|
|
2785
|
+
resourceOwners
|
|
2740
2786
|
};
|
|
2741
2787
|
}
|
|
2742
|
-
|
|
2788
|
+
function trn$5(workspaceId, name) {
|
|
2789
|
+
return `trn:v1:workspace:${workspaceId}:idp:${name}`;
|
|
2790
|
+
}
|
|
2791
|
+
async function planServices$3(client, workspaceId, appName, idps) {
|
|
2743
2792
|
const changeSet = new ChangeSet("IdP services");
|
|
2744
|
-
const
|
|
2793
|
+
const conflicts = [];
|
|
2794
|
+
const unmanaged = [];
|
|
2795
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
2796
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
2745
2797
|
try {
|
|
2746
2798
|
const { idpServices, nextPageToken } = await client.listIdPServices({
|
|
2747
2799
|
workspaceId,
|
|
@@ -2753,13 +2805,19 @@ async function planServices$3(client, workspaceId, idps) {
|
|
|
2753
2805
|
throw error;
|
|
2754
2806
|
}
|
|
2755
2807
|
});
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2808
|
+
const existingServices = {};
|
|
2809
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
2810
|
+
if (!resource.namespace?.name) return;
|
|
2811
|
+
const { metadata } = await client.getMetadata({ trn: trn$5(workspaceId, resource.namespace.name) });
|
|
2812
|
+
existingServices[resource.namespace.name] = {
|
|
2813
|
+
resource,
|
|
2814
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
2815
|
+
};
|
|
2816
|
+
}));
|
|
2761
2817
|
for (const idp of idps) {
|
|
2762
2818
|
const namespaceName = idp.name;
|
|
2819
|
+
const existing = existingServices[namespaceName];
|
|
2820
|
+
const metaRequest = await buildMetaRequest(trn$5(workspaceId, namespaceName), appName);
|
|
2763
2821
|
let authorization;
|
|
2764
2822
|
switch (idp.authorization) {
|
|
2765
2823
|
case "insecure":
|
|
@@ -2772,27 +2830,40 @@ async function planServices$3(client, workspaceId, idps) {
|
|
|
2772
2830
|
authorization = idp.authorization.cel;
|
|
2773
2831
|
break;
|
|
2774
2832
|
}
|
|
2775
|
-
if (
|
|
2833
|
+
if (existing) {
|
|
2834
|
+
if (!existing.label) unmanaged.push({
|
|
2835
|
+
resourceType: "IdP service",
|
|
2836
|
+
resourceName: idp.name
|
|
2837
|
+
});
|
|
2838
|
+
else if (existing.label !== appName) conflicts.push({
|
|
2839
|
+
resourceType: "IdP service",
|
|
2840
|
+
resourceName: idp.name,
|
|
2841
|
+
currentOwner: existing.label
|
|
2842
|
+
});
|
|
2776
2843
|
changeSet.updates.push({
|
|
2777
2844
|
name: namespaceName,
|
|
2778
2845
|
request: {
|
|
2779
2846
|
workspaceId,
|
|
2780
2847
|
namespaceName,
|
|
2781
2848
|
authorization
|
|
2782
|
-
}
|
|
2849
|
+
},
|
|
2850
|
+
metaRequest
|
|
2783
2851
|
});
|
|
2784
|
-
|
|
2852
|
+
delete existingServices[namespaceName];
|
|
2785
2853
|
} else changeSet.creates.push({
|
|
2786
2854
|
name: namespaceName,
|
|
2787
2855
|
request: {
|
|
2788
2856
|
workspaceId,
|
|
2789
2857
|
namespaceName,
|
|
2790
2858
|
authorization
|
|
2791
|
-
}
|
|
2859
|
+
},
|
|
2860
|
+
metaRequest
|
|
2792
2861
|
});
|
|
2793
2862
|
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2863
|
+
Object.entries(existingServices).forEach(([namespaceName]) => {
|
|
2864
|
+
const label = existingServices[namespaceName]?.label;
|
|
2865
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
2866
|
+
if (label === appName) changeSet.deletes.push({
|
|
2796
2867
|
name: namespaceName,
|
|
2797
2868
|
request: {
|
|
2798
2869
|
workspaceId,
|
|
@@ -2800,7 +2871,12 @@ async function planServices$3(client, workspaceId, idps) {
|
|
|
2800
2871
|
}
|
|
2801
2872
|
});
|
|
2802
2873
|
});
|
|
2803
|
-
return
|
|
2874
|
+
return {
|
|
2875
|
+
changeSet,
|
|
2876
|
+
conflicts,
|
|
2877
|
+
unmanaged,
|
|
2878
|
+
resourceOwners
|
|
2879
|
+
};
|
|
2804
2880
|
}
|
|
2805
2881
|
async function planClients(client, workspaceId, idps, deletedServices) {
|
|
2806
2882
|
const changeSet = new ChangeSet("IdP clients");
|
|
@@ -2844,7 +2920,6 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
2844
2920
|
});
|
|
2845
2921
|
existingNameMap.forEach((name) => {
|
|
2846
2922
|
changeSet.deletes.push({
|
|
2847
|
-
tag: "client-deleted",
|
|
2848
2923
|
name,
|
|
2849
2924
|
request: {
|
|
2850
2925
|
workspaceId,
|
|
@@ -2856,8 +2931,12 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
2856
2931
|
}
|
|
2857
2932
|
for (const namespaceName of deletedServices) (await fetchClients(namespaceName)).forEach((client$1) => {
|
|
2858
2933
|
changeSet.deletes.push({
|
|
2859
|
-
|
|
2860
|
-
|
|
2934
|
+
name: client$1.name,
|
|
2935
|
+
request: {
|
|
2936
|
+
workspaceId,
|
|
2937
|
+
namespaceName,
|
|
2938
|
+
name: client$1.name
|
|
2939
|
+
}
|
|
2861
2940
|
});
|
|
2862
2941
|
});
|
|
2863
2942
|
return changeSet;
|
|
@@ -2865,9 +2944,13 @@ async function planClients(client, workspaceId, idps, deletedServices) {
|
|
|
2865
2944
|
|
|
2866
2945
|
//#endregion
|
|
2867
2946
|
//#region src/cli/apply/services/auth.ts
|
|
2868
|
-
async function applyAuth(client,
|
|
2947
|
+
async function applyAuth(client, result, phase = "create-update") {
|
|
2948
|
+
const { changeSet } = result;
|
|
2869
2949
|
if (phase === "create-update") {
|
|
2870
|
-
await Promise.all(changeSet.service.creates.map((create) =>
|
|
2950
|
+
await Promise.all([...changeSet.service.creates.map(async (create) => {
|
|
2951
|
+
await client.createAuthService(create.request);
|
|
2952
|
+
await client.setMetadata(create.metaRequest);
|
|
2953
|
+
}), ...changeSet.service.updates.map((update) => client.setMetadata(update.metaRequest))]);
|
|
2871
2954
|
await Promise.all([...changeSet.idpConfig.creates.map(async (create) => {
|
|
2872
2955
|
if (create.idpConfig.kind === "BuiltInIdP") create.request.idpConfig.config = await protoBuiltinIdPConfig(client, create.request.workspaceId, create.idpConfig);
|
|
2873
2956
|
return client.createAuthIDPConfig(create.request);
|
|
@@ -2888,23 +2971,23 @@ async function applyAuth(client, changeSet, phase = "create-update") {
|
|
|
2888
2971
|
await Promise.all([...changeSet.scim.creates.map((create) => client.createAuthSCIMConfig(create.request)), ...changeSet.scim.updates.map((update) => client.updateAuthSCIMConfig(update.request))]);
|
|
2889
2972
|
await Promise.all([...changeSet.scimResource.creates.map((create) => client.createAuthSCIMResource(create.request)), ...changeSet.scimResource.updates.map((update) => client.updateAuthSCIMResource(update.request))]);
|
|
2890
2973
|
} else if (phase === "delete") {
|
|
2891
|
-
await Promise.all(changeSet.scimResource.deletes.
|
|
2892
|
-
await Promise.all(changeSet.scim.deletes.
|
|
2893
|
-
await Promise.all(changeSet.oauth2Client.deletes.
|
|
2894
|
-
await Promise.all(changeSet.machineUser.deletes.
|
|
2895
|
-
await Promise.all(changeSet.tenantConfig.deletes.
|
|
2896
|
-
await Promise.all(changeSet.userProfileConfig.deletes.
|
|
2897
|
-
await Promise.all(changeSet.idpConfig.deletes.
|
|
2974
|
+
await Promise.all(changeSet.scimResource.deletes.map((del) => client.deleteAuthSCIMResource(del.request)));
|
|
2975
|
+
await Promise.all(changeSet.scim.deletes.map((del) => client.deleteAuthSCIMConfig(del.request)));
|
|
2976
|
+
await Promise.all(changeSet.oauth2Client.deletes.map((del) => client.deleteAuthOAuth2Client(del.request)));
|
|
2977
|
+
await Promise.all(changeSet.machineUser.deletes.map((del) => client.deleteAuthMachineUser(del.request)));
|
|
2978
|
+
await Promise.all(changeSet.tenantConfig.deletes.map((del) => client.deleteTenantConfig(del.request)));
|
|
2979
|
+
await Promise.all(changeSet.userProfileConfig.deletes.map((del) => client.deleteUserProfileConfig(del.request)));
|
|
2980
|
+
await Promise.all(changeSet.idpConfig.deletes.map((del) => client.deleteAuthIDPConfig(del.request)));
|
|
2898
2981
|
await Promise.all(changeSet.service.deletes.map((del) => client.deleteAuthService(del.request)));
|
|
2899
2982
|
}
|
|
2900
2983
|
}
|
|
2901
|
-
async function planAuth(client, workspaceId, application) {
|
|
2984
|
+
async function planAuth({ client, workspaceId, application }) {
|
|
2902
2985
|
const auths = [];
|
|
2903
|
-
|
|
2904
|
-
await
|
|
2905
|
-
auths.push(
|
|
2986
|
+
if (application.authService) {
|
|
2987
|
+
await application.authService.resolveNamespaces();
|
|
2988
|
+
auths.push(application.authService);
|
|
2906
2989
|
}
|
|
2907
|
-
const serviceChangeSet = await planServices$2(client, workspaceId, auths);
|
|
2990
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths);
|
|
2908
2991
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
2909
2992
|
const idpConfigChangeSet = await planIdPConfigs(client, workspaceId, auths, deletedServices);
|
|
2910
2993
|
const userProfileConfigChangeSet = await planUserProfileConfigs(client, workspaceId, auths, deletedServices);
|
|
@@ -2922,19 +3005,30 @@ async function planAuth(client, workspaceId, application) {
|
|
|
2922
3005
|
scimChangeSet.print();
|
|
2923
3006
|
scimResourceChangeSet.print();
|
|
2924
3007
|
return {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
3008
|
+
changeSet: {
|
|
3009
|
+
service: serviceChangeSet,
|
|
3010
|
+
idpConfig: idpConfigChangeSet,
|
|
3011
|
+
userProfileConfig: userProfileConfigChangeSet,
|
|
3012
|
+
tenantConfig: tenantConfigChangeSet,
|
|
3013
|
+
machineUser: machineUserChangeSet,
|
|
3014
|
+
oauth2Client: oauth2ClientChangeSet,
|
|
3015
|
+
scim: scimChangeSet,
|
|
3016
|
+
scimResource: scimResourceChangeSet
|
|
3017
|
+
},
|
|
3018
|
+
conflicts,
|
|
3019
|
+
unmanaged,
|
|
3020
|
+
resourceOwners
|
|
2933
3021
|
};
|
|
2934
3022
|
}
|
|
2935
|
-
|
|
3023
|
+
function trn$4(workspaceId, name) {
|
|
3024
|
+
return `trn:v1:workspace:${workspaceId}:auth:${name}`;
|
|
3025
|
+
}
|
|
3026
|
+
async function planServices$2(client, workspaceId, appName, auths) {
|
|
2936
3027
|
const changeSet = new ChangeSet("Auth services");
|
|
2937
|
-
const
|
|
3028
|
+
const conflicts = [];
|
|
3029
|
+
const unmanaged = [];
|
|
3030
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
3031
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
2938
3032
|
try {
|
|
2939
3033
|
const { authServices, nextPageToken } = await client.listAuthServices({
|
|
2940
3034
|
workspaceId,
|
|
@@ -2946,23 +3040,46 @@ async function planServices$2(client, workspaceId, auths) {
|
|
|
2946
3040
|
throw error;
|
|
2947
3041
|
}
|
|
2948
3042
|
});
|
|
2949
|
-
const
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
}
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3043
|
+
const existingServices = {};
|
|
3044
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
3045
|
+
if (!resource.namespace?.name) return;
|
|
3046
|
+
const { metadata } = await client.getMetadata({ trn: trn$4(workspaceId, resource.namespace.name) });
|
|
3047
|
+
existingServices[resource.namespace.name] = {
|
|
3048
|
+
resource,
|
|
3049
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
3050
|
+
};
|
|
3051
|
+
}));
|
|
3052
|
+
for (const { config } of auths) {
|
|
3053
|
+
const existing = existingServices[config.name];
|
|
3054
|
+
const metaRequest = await buildMetaRequest(trn$4(workspaceId, config.name), appName);
|
|
3055
|
+
if (existing) {
|
|
3056
|
+
if (!existing.label) unmanaged.push({
|
|
3057
|
+
resourceType: "Auth service",
|
|
3058
|
+
resourceName: config.name
|
|
3059
|
+
});
|
|
3060
|
+
else if (existing.label !== appName) conflicts.push({
|
|
3061
|
+
resourceType: "Auth service",
|
|
3062
|
+
resourceName: config.name,
|
|
3063
|
+
currentOwner: existing.label
|
|
3064
|
+
});
|
|
3065
|
+
changeSet.updates.push({
|
|
3066
|
+
name: config.name,
|
|
3067
|
+
metaRequest
|
|
3068
|
+
});
|
|
3069
|
+
delete existingServices[config.name];
|
|
3070
|
+
} else changeSet.creates.push({
|
|
3071
|
+
name: config.name,
|
|
3072
|
+
request: {
|
|
3073
|
+
workspaceId,
|
|
3074
|
+
namespaceName: config.name
|
|
3075
|
+
},
|
|
3076
|
+
metaRequest
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
Object.entries(existingServices).forEach(([namespaceName]) => {
|
|
3080
|
+
const label = existingServices[namespaceName]?.label;
|
|
3081
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
3082
|
+
if (label === appName) changeSet.deletes.push({
|
|
2966
3083
|
name: namespaceName,
|
|
2967
3084
|
request: {
|
|
2968
3085
|
workspaceId,
|
|
@@ -2970,7 +3087,12 @@ async function planServices$2(client, workspaceId, auths) {
|
|
|
2970
3087
|
}
|
|
2971
3088
|
});
|
|
2972
3089
|
});
|
|
2973
|
-
return
|
|
3090
|
+
return {
|
|
3091
|
+
changeSet,
|
|
3092
|
+
conflicts,
|
|
3093
|
+
unmanaged,
|
|
3094
|
+
resourceOwners
|
|
3095
|
+
};
|
|
2974
3096
|
}
|
|
2975
3097
|
async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
2976
3098
|
const changeSet = new ChangeSet("Auth idpConfigs");
|
|
@@ -3018,7 +3140,6 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3018
3140
|
});
|
|
3019
3141
|
existingNameSet.forEach((name) => {
|
|
3020
3142
|
changeSet.deletes.push({
|
|
3021
|
-
tag: "idp-config-deleted",
|
|
3022
3143
|
name,
|
|
3023
3144
|
request: {
|
|
3024
3145
|
workspaceId,
|
|
@@ -3030,8 +3151,12 @@ async function planIdPConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3030
3151
|
}
|
|
3031
3152
|
for (const namespaceName of deletedServices) (await fetchIdPConfigs(namespaceName)).forEach((idpConfig) => {
|
|
3032
3153
|
changeSet.deletes.push({
|
|
3033
|
-
|
|
3034
|
-
|
|
3154
|
+
name: idpConfig.name,
|
|
3155
|
+
request: {
|
|
3156
|
+
workspaceId,
|
|
3157
|
+
namespaceName,
|
|
3158
|
+
name: idpConfig.name
|
|
3159
|
+
}
|
|
3035
3160
|
});
|
|
3036
3161
|
});
|
|
3037
3162
|
return changeSet;
|
|
@@ -3157,7 +3282,6 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
|
|
|
3157
3282
|
}
|
|
3158
3283
|
});
|
|
3159
3284
|
else changeSet.deletes.push({
|
|
3160
|
-
tag: "user-profile-config-deleted",
|
|
3161
3285
|
name,
|
|
3162
3286
|
request: {
|
|
3163
3287
|
workspaceId,
|
|
@@ -3176,8 +3300,11 @@ async function planUserProfileConfigs(client, workspaceId, auths, deletedService
|
|
|
3176
3300
|
throw error;
|
|
3177
3301
|
}
|
|
3178
3302
|
changeSet.deletes.push({
|
|
3179
|
-
|
|
3180
|
-
|
|
3303
|
+
name: `${namespaceName}-user-profile-config`,
|
|
3304
|
+
request: {
|
|
3305
|
+
workspaceId,
|
|
3306
|
+
namespaceName
|
|
3307
|
+
}
|
|
3181
3308
|
});
|
|
3182
3309
|
}
|
|
3183
3310
|
return changeSet;
|
|
@@ -3232,7 +3359,6 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3232
3359
|
}
|
|
3233
3360
|
});
|
|
3234
3361
|
else changeSet.deletes.push({
|
|
3235
|
-
tag: "tenant-config-deleted",
|
|
3236
3362
|
name,
|
|
3237
3363
|
request: {
|
|
3238
3364
|
workspaceId,
|
|
@@ -3251,8 +3377,11 @@ async function planTenantConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3251
3377
|
throw error;
|
|
3252
3378
|
}
|
|
3253
3379
|
changeSet.deletes.push({
|
|
3254
|
-
|
|
3255
|
-
|
|
3380
|
+
name: `${namespaceName}-tenant-config`,
|
|
3381
|
+
request: {
|
|
3382
|
+
workspaceId,
|
|
3383
|
+
namespaceName
|
|
3384
|
+
}
|
|
3256
3385
|
});
|
|
3257
3386
|
}
|
|
3258
3387
|
return changeSet;
|
|
@@ -3321,7 +3450,6 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
3321
3450
|
}
|
|
3322
3451
|
existingNameSet.forEach((name) => {
|
|
3323
3452
|
changeSet.deletes.push({
|
|
3324
|
-
tag: "machine-user-deleted",
|
|
3325
3453
|
name,
|
|
3326
3454
|
request: {
|
|
3327
3455
|
workspaceId,
|
|
@@ -3333,8 +3461,12 @@ async function planMachineUsers(client, workspaceId, auths, deletedServices) {
|
|
|
3333
3461
|
}
|
|
3334
3462
|
for (const namespaceName of deletedServices) (await fetchMachineUsers(namespaceName)).forEach((machineUser) => {
|
|
3335
3463
|
changeSet.deletes.push({
|
|
3336
|
-
|
|
3337
|
-
|
|
3464
|
+
name: machineUser.name,
|
|
3465
|
+
request: {
|
|
3466
|
+
workspaceId,
|
|
3467
|
+
authNamespace: namespaceName,
|
|
3468
|
+
name: machineUser.name
|
|
3469
|
+
}
|
|
3338
3470
|
});
|
|
3339
3471
|
});
|
|
3340
3472
|
return changeSet;
|
|
@@ -3391,7 +3523,6 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
3391
3523
|
}
|
|
3392
3524
|
existingNameSet.forEach((name) => {
|
|
3393
3525
|
changeSet.deletes.push({
|
|
3394
|
-
tag: "oauth2-client-deleted",
|
|
3395
3526
|
name,
|
|
3396
3527
|
request: {
|
|
3397
3528
|
workspaceId,
|
|
@@ -3403,8 +3534,12 @@ async function planOAuth2Clients(client, workspaceId, auths, deletedServices) {
|
|
|
3403
3534
|
}
|
|
3404
3535
|
for (const namespaceName of deletedServices) (await fetchOAuth2Clients(namespaceName)).forEach((oauth2Client) => {
|
|
3405
3536
|
changeSet.deletes.push({
|
|
3406
|
-
|
|
3407
|
-
|
|
3537
|
+
name: oauth2Client.name,
|
|
3538
|
+
request: {
|
|
3539
|
+
workspaceId,
|
|
3540
|
+
namespaceName,
|
|
3541
|
+
name: oauth2Client.name
|
|
3542
|
+
}
|
|
3408
3543
|
});
|
|
3409
3544
|
});
|
|
3410
3545
|
return changeSet;
|
|
@@ -3460,7 +3595,6 @@ async function planSCIMConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3460
3595
|
}
|
|
3461
3596
|
});
|
|
3462
3597
|
else changeSet.deletes.push({
|
|
3463
|
-
tag: "scim-config-deleted",
|
|
3464
3598
|
name,
|
|
3465
3599
|
request: {
|
|
3466
3600
|
workspaceId,
|
|
@@ -3479,8 +3613,11 @@ async function planSCIMConfigs(client, workspaceId, auths, deletedServices) {
|
|
|
3479
3613
|
throw error;
|
|
3480
3614
|
}
|
|
3481
3615
|
changeSet.deletes.push({
|
|
3482
|
-
|
|
3483
|
-
|
|
3616
|
+
name: `${namespaceName}-scim-config`,
|
|
3617
|
+
request: {
|
|
3618
|
+
workspaceId,
|
|
3619
|
+
namespaceName
|
|
3620
|
+
}
|
|
3484
3621
|
});
|
|
3485
3622
|
}
|
|
3486
3623
|
return changeSet;
|
|
@@ -3548,7 +3685,6 @@ async function planSCIMResources(client, workspaceId, auths, deletedServices) {
|
|
|
3548
3685
|
});
|
|
3549
3686
|
existingNameSet.forEach((name) => {
|
|
3550
3687
|
changeSet.deletes.push({
|
|
3551
|
-
tag: "scim-resource-deleted",
|
|
3552
3688
|
name,
|
|
3553
3689
|
request: {
|
|
3554
3690
|
workspaceId,
|
|
@@ -3560,8 +3696,12 @@ async function planSCIMResources(client, workspaceId, auths, deletedServices) {
|
|
|
3560
3696
|
}
|
|
3561
3697
|
for (const namespaceName of deletedServices) (await fetchSCIMResources(namespaceName)).forEach((scimResource) => {
|
|
3562
3698
|
changeSet.deletes.push({
|
|
3563
|
-
|
|
3564
|
-
|
|
3699
|
+
name: scimResource.name,
|
|
3700
|
+
request: {
|
|
3701
|
+
workspaceId,
|
|
3702
|
+
namespaceName,
|
|
3703
|
+
name: scimResource.name
|
|
3704
|
+
}
|
|
3565
3705
|
});
|
|
3566
3706
|
});
|
|
3567
3707
|
return changeSet;
|
|
@@ -3640,15 +3780,91 @@ function protoSCIMAttribute(attr) {
|
|
|
3640
3780
|
};
|
|
3641
3781
|
}
|
|
3642
3782
|
|
|
3783
|
+
//#endregion
|
|
3784
|
+
//#region src/cli/apply/services/confirm.ts
|
|
3785
|
+
async function confirmOwnerConflict(conflicts, appName, yes) {
|
|
3786
|
+
if (conflicts.length === 0) return;
|
|
3787
|
+
const currentOwners = [...new Set(conflicts.map((c) => c.currentOwner))];
|
|
3788
|
+
consola.warn("Application name mismatch detected:");
|
|
3789
|
+
console.log(` ${chalk.yellow("Current application(s)")}: ${currentOwners.map((o) => chalk.bold(`"${o}"`)).join(", ")}`);
|
|
3790
|
+
console.log(` ${chalk.green("New application")}: ${chalk.bold(`"${appName}"`)}`);
|
|
3791
|
+
console.log("");
|
|
3792
|
+
console.log(` ${chalk.cyan("Resources")}:`);
|
|
3793
|
+
for (const c of conflicts) console.log(` • ${chalk.bold(c.resourceType)} ${chalk.cyan(`"${c.resourceName}"`)}`);
|
|
3794
|
+
if (yes) {
|
|
3795
|
+
consola.success("Updating resources (--yes flag specified)...");
|
|
3796
|
+
return;
|
|
3797
|
+
}
|
|
3798
|
+
const promptMessage = currentOwners.length === 1 ? `Update these resources to be managed by "${appName}"?\n${chalk.gray("(Common when renaming your application)")}` : `Update these resources to be managed by "${appName}"?`;
|
|
3799
|
+
if (!await consola.prompt(promptMessage, {
|
|
3800
|
+
type: "confirm",
|
|
3801
|
+
initial: false
|
|
3802
|
+
})) throw new Error(ml`
|
|
3803
|
+
Apply cancelled. Resources remain managed by their current applications.
|
|
3804
|
+
To override, run again and confirm, or use --yes flag.
|
|
3805
|
+
`);
|
|
3806
|
+
}
|
|
3807
|
+
async function confirmUnmanagedResources(resources, appName, yes) {
|
|
3808
|
+
if (resources.length === 0) return;
|
|
3809
|
+
consola.warn("Unmanaged resources detected:");
|
|
3810
|
+
console.log(` ${chalk.cyan("Resources")}:`);
|
|
3811
|
+
for (const r of resources) console.log(` • ${chalk.bold(r.resourceType)} ${chalk.cyan(`"${r.resourceName}"`)}`);
|
|
3812
|
+
console.log("");
|
|
3813
|
+
console.log(" These resources are not managed by any application.");
|
|
3814
|
+
if (yes) {
|
|
3815
|
+
consola.success(`Adding to "${appName}" (--yes flag specified)...`);
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
if (!await consola.prompt(`Add these resources to "${appName}"?`, {
|
|
3819
|
+
type: "confirm",
|
|
3820
|
+
initial: false
|
|
3821
|
+
})) throw new Error(ml`
|
|
3822
|
+
Apply cancelled. Resources remain unmanaged.
|
|
3823
|
+
To override, run again and confirm, or use --yes flag.
|
|
3824
|
+
`);
|
|
3825
|
+
}
|
|
3826
|
+
async function confirmImportantResourceDeletion(resources, yes) {
|
|
3827
|
+
if (resources.length === 0) return;
|
|
3828
|
+
consola.warn("The following resources will be deleted:");
|
|
3829
|
+
console.log(` ${chalk.cyan("Resources")}:`);
|
|
3830
|
+
for (const r of resources) console.log(` • ${chalk.bold(r.resourceType)} ${chalk.red(`"${r.resourceName}"`)}`);
|
|
3831
|
+
console.log("");
|
|
3832
|
+
console.log(chalk.yellow(" Deleting these resources will permanently remove all associated data."));
|
|
3833
|
+
if (yes) {
|
|
3834
|
+
consola.success("Deleting resources (--yes flag specified)...");
|
|
3835
|
+
return;
|
|
3836
|
+
}
|
|
3837
|
+
if (!await consola.prompt("Are you sure you want to delete these resources?", {
|
|
3838
|
+
type: "confirm",
|
|
3839
|
+
initial: false
|
|
3840
|
+
})) throw new Error(ml`
|
|
3841
|
+
Apply cancelled. Resources will not be deleted.
|
|
3842
|
+
To override, run again and confirm, or use --yes flag.
|
|
3843
|
+
`);
|
|
3844
|
+
}
|
|
3845
|
+
|
|
3643
3846
|
//#endregion
|
|
3644
3847
|
//#region src/cli/apply/services/executor.ts
|
|
3645
|
-
async function applyExecutor(client,
|
|
3646
|
-
|
|
3848
|
+
async function applyExecutor(client, result, phase = "create-update") {
|
|
3849
|
+
const { changeSet } = result;
|
|
3850
|
+
if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
|
|
3851
|
+
await client.createExecutorExecutor(create.request);
|
|
3852
|
+
await client.setMetadata(create.metaRequest);
|
|
3853
|
+
}), ...changeSet.updates.map(async (update) => {
|
|
3854
|
+
await client.updateExecutorExecutor(update.request);
|
|
3855
|
+
await client.setMetadata(update.metaRequest);
|
|
3856
|
+
})]);
|
|
3647
3857
|
else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteExecutorExecutor(del.request)));
|
|
3648
3858
|
}
|
|
3649
|
-
|
|
3859
|
+
function trn$3(workspaceId, name) {
|
|
3860
|
+
return `trn:v1:workspace:${workspaceId}:executor:${name}`;
|
|
3861
|
+
}
|
|
3862
|
+
async function planExecutor({ client, workspaceId, application }) {
|
|
3650
3863
|
const changeSet = new ChangeSet("Executors");
|
|
3651
|
-
const
|
|
3864
|
+
const conflicts = [];
|
|
3865
|
+
const unmanaged = [];
|
|
3866
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
3867
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
3652
3868
|
try {
|
|
3653
3869
|
const { executors: executors$1, nextPageToken } = await client.listExecutorExecutors({
|
|
3654
3870
|
workspaceId,
|
|
@@ -3660,29 +3876,50 @@ async function planExecutor(client, workspaceId, application) {
|
|
|
3660
3876
|
throw error;
|
|
3661
3877
|
}
|
|
3662
3878
|
});
|
|
3663
|
-
const
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3879
|
+
const existingExecutors = {};
|
|
3880
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
3881
|
+
const { metadata } = await client.getMetadata({ trn: trn$3(workspaceId, resource.name) });
|
|
3882
|
+
existingExecutors[resource.name] = {
|
|
3883
|
+
resource,
|
|
3884
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
3885
|
+
};
|
|
3886
|
+
}));
|
|
3667
3887
|
const executors = await application.executorService?.loadExecutors() ?? {};
|
|
3668
|
-
for (const executor of Object.values(executors))
|
|
3669
|
-
|
|
3888
|
+
for (const executor of Object.values(executors)) {
|
|
3889
|
+
const existing = existingExecutors[executor.name];
|
|
3890
|
+
const metaRequest = await buildMetaRequest(trn$3(workspaceId, executor.name), application.name);
|
|
3891
|
+
if (existing) {
|
|
3892
|
+
if (!existing.label) unmanaged.push({
|
|
3893
|
+
resourceType: "Executor",
|
|
3894
|
+
resourceName: executor.name
|
|
3895
|
+
});
|
|
3896
|
+
else if (existing.label !== application.name) conflicts.push({
|
|
3897
|
+
resourceType: "Executor",
|
|
3898
|
+
resourceName: executor.name,
|
|
3899
|
+
currentOwner: existing.label
|
|
3900
|
+
});
|
|
3901
|
+
changeSet.updates.push({
|
|
3902
|
+
name: executor.name,
|
|
3903
|
+
request: {
|
|
3904
|
+
workspaceId,
|
|
3905
|
+
executor: protoExecutor(application.name, executor, application.env)
|
|
3906
|
+
},
|
|
3907
|
+
metaRequest
|
|
3908
|
+
});
|
|
3909
|
+
delete existingExecutors[executor.name];
|
|
3910
|
+
} else changeSet.creates.push({
|
|
3670
3911
|
name: executor.name,
|
|
3671
3912
|
request: {
|
|
3672
3913
|
workspaceId,
|
|
3673
|
-
executor: protoExecutor(executor)
|
|
3674
|
-
}
|
|
3914
|
+
executor: protoExecutor(application.name, executor, application.env)
|
|
3915
|
+
},
|
|
3916
|
+
metaRequest
|
|
3675
3917
|
});
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
executor: protoExecutor(executor)
|
|
3682
|
-
}
|
|
3683
|
-
});
|
|
3684
|
-
existingNameSet.forEach((name) => {
|
|
3685
|
-
changeSet.deletes.push({
|
|
3918
|
+
}
|
|
3919
|
+
Object.entries(existingExecutors).forEach(([name]) => {
|
|
3920
|
+
const label = existingExecutors[name]?.label;
|
|
3921
|
+
if (label && label !== application.name) resourceOwners.add(label);
|
|
3922
|
+
if (label === application.name) changeSet.deletes.push({
|
|
3686
3923
|
name,
|
|
3687
3924
|
request: {
|
|
3688
3925
|
workspaceId,
|
|
@@ -3691,9 +3928,14 @@ async function planExecutor(client, workspaceId, application) {
|
|
|
3691
3928
|
});
|
|
3692
3929
|
});
|
|
3693
3930
|
changeSet.print();
|
|
3694
|
-
return
|
|
3931
|
+
return {
|
|
3932
|
+
changeSet,
|
|
3933
|
+
conflicts,
|
|
3934
|
+
unmanaged,
|
|
3935
|
+
resourceOwners
|
|
3936
|
+
};
|
|
3695
3937
|
}
|
|
3696
|
-
function protoExecutor(executor) {
|
|
3938
|
+
function protoExecutor(appName, executor, env) {
|
|
3697
3939
|
const trigger = executor.trigger;
|
|
3698
3940
|
let triggerType;
|
|
3699
3941
|
let triggerConfig;
|
|
@@ -3782,7 +4024,7 @@ function protoExecutor(executor) {
|
|
|
3782
4024
|
targetConfig = { config: {
|
|
3783
4025
|
case: "tailorGraphql",
|
|
3784
4026
|
value: {
|
|
3785
|
-
appName: target.appName,
|
|
4027
|
+
appName: target.appName ?? appName,
|
|
3786
4028
|
query: target.query,
|
|
3787
4029
|
variables: target.variables ? { expr: `(${target.variables.toString()})(args)` } : void 0,
|
|
3788
4030
|
invoker: target.invoker ? {
|
|
@@ -3803,7 +4045,7 @@ function protoExecutor(executor) {
|
|
|
3803
4045
|
value: {
|
|
3804
4046
|
name: `${executor.name}__target`,
|
|
3805
4047
|
script,
|
|
3806
|
-
variables: { expr:
|
|
4048
|
+
variables: { expr: `({ ...args, appNamespace: args.namespaceName, env: ${JSON.stringify(env)} })` },
|
|
3807
4049
|
invoker: target.invoker ? {
|
|
3808
4050
|
namespace: target.invoker.authName,
|
|
3809
4051
|
machineUserName: target.invoker.machineUser
|
|
@@ -3861,35 +4103,53 @@ const SCALAR_TYPE_MAP = {
|
|
|
3861
4103
|
name: "Time"
|
|
3862
4104
|
}
|
|
3863
4105
|
};
|
|
3864
|
-
async function applyPipeline(client,
|
|
4106
|
+
async function applyPipeline(client, result, phase = "create-update") {
|
|
4107
|
+
const { changeSet } = result;
|
|
3865
4108
|
if (phase === "create-update") {
|
|
3866
|
-
await Promise.all([...changeSet.service.creates.map(
|
|
4109
|
+
await Promise.all([...changeSet.service.creates.map(async (create) => {
|
|
4110
|
+
await client.createPipelineService(create.request);
|
|
4111
|
+
await client.setMetadata(create.metaRequest);
|
|
4112
|
+
}), ...changeSet.service.updates.map(async (update) => {
|
|
4113
|
+
await client.updatePipelineService(update.request);
|
|
4114
|
+
await client.setMetadata(update.metaRequest);
|
|
4115
|
+
})]);
|
|
3867
4116
|
await Promise.all([...changeSet.resolver.creates.map((create) => client.createPipelineResolver(create.request)), ...changeSet.resolver.updates.map((update) => client.updatePipelineResolver(update.request))]);
|
|
3868
4117
|
} else if (phase === "delete") {
|
|
3869
|
-
await Promise.all(changeSet.resolver.deletes.
|
|
4118
|
+
await Promise.all(changeSet.resolver.deletes.map((del) => client.deletePipelineResolver(del.request)));
|
|
3870
4119
|
await Promise.all(changeSet.service.deletes.map((del) => client.deletePipelineService(del.request)));
|
|
3871
4120
|
}
|
|
3872
4121
|
}
|
|
3873
|
-
async function planPipeline(client, workspaceId, application) {
|
|
4122
|
+
async function planPipeline({ client, workspaceId, application }) {
|
|
3874
4123
|
const pipelines = [];
|
|
3875
|
-
for (const
|
|
4124
|
+
for (const pipeline of application.resolverServices) {
|
|
3876
4125
|
await pipeline.loadResolvers();
|
|
3877
4126
|
pipelines.push(pipeline);
|
|
3878
4127
|
}
|
|
3879
4128
|
const executors = Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
3880
|
-
const serviceChangeSet = await planServices$1(client, workspaceId, pipelines);
|
|
4129
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$1(client, workspaceId, application.name, pipelines);
|
|
3881
4130
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
3882
|
-
const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, deletedServices);
|
|
4131
|
+
const resolverChangeSet = await planResolvers(client, workspaceId, pipelines, executors, deletedServices, application.env);
|
|
3883
4132
|
serviceChangeSet.print();
|
|
3884
4133
|
resolverChangeSet.print();
|
|
3885
4134
|
return {
|
|
3886
|
-
|
|
3887
|
-
|
|
4135
|
+
changeSet: {
|
|
4136
|
+
service: serviceChangeSet,
|
|
4137
|
+
resolver: resolverChangeSet
|
|
4138
|
+
},
|
|
4139
|
+
conflicts,
|
|
4140
|
+
unmanaged,
|
|
4141
|
+
resourceOwners
|
|
3888
4142
|
};
|
|
3889
4143
|
}
|
|
3890
|
-
|
|
4144
|
+
function trn$2(workspaceId, name) {
|
|
4145
|
+
return `trn:v1:workspace:${workspaceId}:pipeline:${name}`;
|
|
4146
|
+
}
|
|
4147
|
+
async function planServices$1(client, workspaceId, appName, pipelines) {
|
|
3891
4148
|
const changeSet = new ChangeSet("Pipeline services");
|
|
3892
|
-
const
|
|
4149
|
+
const conflicts = [];
|
|
4150
|
+
const unmanaged = [];
|
|
4151
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
4152
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
3893
4153
|
try {
|
|
3894
4154
|
const { pipelineServices, nextPageToken } = await client.listPipelineServices({
|
|
3895
4155
|
workspaceId,
|
|
@@ -3901,29 +4161,50 @@ async function planServices$1(client, workspaceId, pipelines) {
|
|
|
3901
4161
|
throw error;
|
|
3902
4162
|
}
|
|
3903
4163
|
});
|
|
3904
|
-
const
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
4164
|
+
const existingServices = {};
|
|
4165
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
4166
|
+
if (!resource.namespace?.name) return;
|
|
4167
|
+
const { metadata } = await client.getMetadata({ trn: trn$2(workspaceId, resource.namespace.name) });
|
|
4168
|
+
existingServices[resource.namespace.name] = {
|
|
4169
|
+
resource,
|
|
4170
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
4171
|
+
};
|
|
4172
|
+
}));
|
|
4173
|
+
for (const pipeline of pipelines) {
|
|
4174
|
+
const existing = existingServices[pipeline.namespace];
|
|
4175
|
+
const metaRequest = await buildMetaRequest(trn$2(workspaceId, pipeline.namespace), appName);
|
|
4176
|
+
if (existing) {
|
|
4177
|
+
if (!existing.label) unmanaged.push({
|
|
4178
|
+
resourceType: "Pipeline service",
|
|
4179
|
+
resourceName: pipeline.namespace
|
|
4180
|
+
});
|
|
4181
|
+
else if (existing.label !== appName) conflicts.push({
|
|
4182
|
+
resourceType: "Pipeline service",
|
|
4183
|
+
resourceName: pipeline.namespace,
|
|
4184
|
+
currentOwner: existing.label
|
|
4185
|
+
});
|
|
4186
|
+
changeSet.updates.push({
|
|
4187
|
+
name: pipeline.namespace,
|
|
4188
|
+
request: {
|
|
4189
|
+
workspaceId,
|
|
4190
|
+
namespaceName: pipeline.namespace
|
|
4191
|
+
},
|
|
4192
|
+
metaRequest
|
|
4193
|
+
});
|
|
4194
|
+
delete existingServices[pipeline.namespace];
|
|
4195
|
+
} else changeSet.creates.push({
|
|
3911
4196
|
name: pipeline.namespace,
|
|
3912
4197
|
request: {
|
|
3913
4198
|
workspaceId,
|
|
3914
4199
|
namespaceName: pipeline.namespace
|
|
3915
|
-
}
|
|
4200
|
+
},
|
|
4201
|
+
metaRequest
|
|
3916
4202
|
});
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
namespaceName: pipeline.namespace
|
|
3923
|
-
}
|
|
3924
|
-
});
|
|
3925
|
-
existingNameSet.forEach((namespaceName) => {
|
|
3926
|
-
changeSet.deletes.push({
|
|
4203
|
+
}
|
|
4204
|
+
Object.entries(existingServices).forEach(([namespaceName]) => {
|
|
4205
|
+
const label = existingServices[namespaceName]?.label;
|
|
4206
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
4207
|
+
if (label === appName) changeSet.deletes.push({
|
|
3927
4208
|
name: namespaceName,
|
|
3928
4209
|
request: {
|
|
3929
4210
|
workspaceId,
|
|
@@ -3931,9 +4212,14 @@ async function planServices$1(client, workspaceId, pipelines) {
|
|
|
3931
4212
|
}
|
|
3932
4213
|
});
|
|
3933
4214
|
});
|
|
3934
|
-
return
|
|
4215
|
+
return {
|
|
4216
|
+
changeSet,
|
|
4217
|
+
conflicts,
|
|
4218
|
+
unmanaged,
|
|
4219
|
+
resourceOwners
|
|
4220
|
+
};
|
|
3935
4221
|
}
|
|
3936
|
-
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices) {
|
|
4222
|
+
async function planResolvers(client, workspaceId, pipelines, executors, deletedServices, env) {
|
|
3937
4223
|
const changeSet = new ChangeSet("Pipeline resolvers");
|
|
3938
4224
|
const fetchResolvers = (namespaceName) => {
|
|
3939
4225
|
return fetchAll(async (pageToken) => {
|
|
@@ -3964,7 +4250,7 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3964
4250
|
request: {
|
|
3965
4251
|
workspaceId,
|
|
3966
4252
|
namespaceName: pipeline.namespace,
|
|
3967
|
-
pipelineResolver: processResolver(resolver, executorUsedResolvers)
|
|
4253
|
+
pipelineResolver: processResolver(resolver, executorUsedResolvers, env)
|
|
3968
4254
|
}
|
|
3969
4255
|
});
|
|
3970
4256
|
existingNameSet.delete(resolver.name);
|
|
@@ -3973,12 +4259,11 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3973
4259
|
request: {
|
|
3974
4260
|
workspaceId,
|
|
3975
4261
|
namespaceName: pipeline.namespace,
|
|
3976
|
-
pipelineResolver: processResolver(resolver, executorUsedResolvers)
|
|
4262
|
+
pipelineResolver: processResolver(resolver, executorUsedResolvers, env)
|
|
3977
4263
|
}
|
|
3978
4264
|
});
|
|
3979
4265
|
existingNameSet.forEach((name) => {
|
|
3980
4266
|
changeSet.deletes.push({
|
|
3981
|
-
tag: "resolver-deleted",
|
|
3982
4267
|
name,
|
|
3983
4268
|
request: {
|
|
3984
4269
|
workspaceId,
|
|
@@ -3990,13 +4275,17 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
3990
4275
|
}
|
|
3991
4276
|
for (const namespaceName of deletedServices) (await fetchResolvers(namespaceName)).forEach((resolver) => {
|
|
3992
4277
|
changeSet.deletes.push({
|
|
3993
|
-
|
|
3994
|
-
|
|
4278
|
+
name: resolver.name,
|
|
4279
|
+
request: {
|
|
4280
|
+
workspaceId,
|
|
4281
|
+
namespaceName,
|
|
4282
|
+
resolverName: resolver.name
|
|
4283
|
+
}
|
|
3995
4284
|
});
|
|
3996
4285
|
});
|
|
3997
4286
|
return changeSet;
|
|
3998
4287
|
}
|
|
3999
|
-
function processResolver(resolver, executorUsedResolvers) {
|
|
4288
|
+
function processResolver(resolver, executorUsedResolvers, env) {
|
|
4000
4289
|
const functionPath = path.join(getDistDir(), "functions", `${resolver.name}__body.js`);
|
|
4001
4290
|
let functionCode = "";
|
|
4002
4291
|
try {
|
|
@@ -4010,7 +4299,7 @@ function processResolver(resolver, executorUsedResolvers) {
|
|
|
4010
4299
|
description: `${resolver.name} function body`,
|
|
4011
4300
|
operationType: PipelineResolver_OperationType.FUNCTION,
|
|
4012
4301
|
operationSource: functionCode,
|
|
4013
|
-
operationHook: { expr: `({ ...context.pipeline, input: context.args, user: ${tailorUserMap} });` },
|
|
4302
|
+
operationHook: { expr: `({ ...context.pipeline, input: context.args, user: ${tailorUserMap}, env: ${JSON.stringify(env)} });` },
|
|
4014
4303
|
postScript: `args.body`
|
|
4015
4304
|
}];
|
|
4016
4305
|
const typeBaseName = inflection.camelize(resolver.name);
|
|
@@ -4065,13 +4354,26 @@ function protoFields(fields, baseName, isInput) {
|
|
|
4065
4354
|
|
|
4066
4355
|
//#endregion
|
|
4067
4356
|
//#region src/cli/apply/services/staticwebsite.ts
|
|
4068
|
-
async function applyStaticWebsite(client,
|
|
4069
|
-
|
|
4357
|
+
async function applyStaticWebsite(client, result, phase = "create-update") {
|
|
4358
|
+
const { changeSet } = result;
|
|
4359
|
+
if (phase === "create-update") await Promise.all([...changeSet.creates.map(async (create) => {
|
|
4360
|
+
await client.createStaticWebsite(create.request);
|
|
4361
|
+
await client.setMetadata(create.metaRequest);
|
|
4362
|
+
}), ...changeSet.updates.map(async (update) => {
|
|
4363
|
+
await client.updateStaticWebsite(update.request);
|
|
4364
|
+
await client.setMetadata(update.metaRequest);
|
|
4365
|
+
})]);
|
|
4070
4366
|
else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteStaticWebsite(del.request)));
|
|
4071
4367
|
}
|
|
4072
|
-
|
|
4368
|
+
function trn$1(workspaceId, name) {
|
|
4369
|
+
return `trn:v1:workspace:${workspaceId}:staticwebsite:${name}`;
|
|
4370
|
+
}
|
|
4371
|
+
async function planStaticWebsite({ client, workspaceId, application }) {
|
|
4073
4372
|
const changeSet = new ChangeSet("StaticWebsites");
|
|
4074
|
-
const
|
|
4373
|
+
const conflicts = [];
|
|
4374
|
+
const unmanaged = [];
|
|
4375
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
4376
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
4075
4377
|
try {
|
|
4076
4378
|
const { staticwebsites, nextPageToken } = await client.listStaticWebsites({
|
|
4077
4379
|
workspaceId,
|
|
@@ -4083,14 +4385,29 @@ async function planStaticWebsite(client, workspaceId, application) {
|
|
|
4083
4385
|
throw error;
|
|
4084
4386
|
}
|
|
4085
4387
|
});
|
|
4086
|
-
const
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4388
|
+
const existingWebsites = {};
|
|
4389
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
4390
|
+
const { metadata } = await client.getMetadata({ trn: trn$1(workspaceId, resource.name) });
|
|
4391
|
+
existingWebsites[resource.name] = {
|
|
4392
|
+
resource,
|
|
4393
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
4394
|
+
};
|
|
4395
|
+
}));
|
|
4090
4396
|
for (const websiteService of application.staticWebsiteServices) {
|
|
4091
4397
|
const config = websiteService;
|
|
4092
4398
|
const name = websiteService.name;
|
|
4093
|
-
|
|
4399
|
+
const existing = existingWebsites[name];
|
|
4400
|
+
const metaRequest = await buildMetaRequest(trn$1(workspaceId, name), application.name);
|
|
4401
|
+
if (existing) {
|
|
4402
|
+
if (!existing.label) unmanaged.push({
|
|
4403
|
+
resourceType: "StaticWebsite",
|
|
4404
|
+
resourceName: name
|
|
4405
|
+
});
|
|
4406
|
+
else if (existing.label !== application.name) conflicts.push({
|
|
4407
|
+
resourceType: "StaticWebsite",
|
|
4408
|
+
resourceName: name,
|
|
4409
|
+
currentOwner: existing.label
|
|
4410
|
+
});
|
|
4094
4411
|
changeSet.updates.push({
|
|
4095
4412
|
name,
|
|
4096
4413
|
request: {
|
|
@@ -4100,9 +4417,10 @@ async function planStaticWebsite(client, workspaceId, application) {
|
|
|
4100
4417
|
description: config.description || "",
|
|
4101
4418
|
allowedIpAddresses: config.allowedIpAddresses || []
|
|
4102
4419
|
}
|
|
4103
|
-
}
|
|
4420
|
+
},
|
|
4421
|
+
metaRequest
|
|
4104
4422
|
});
|
|
4105
|
-
|
|
4423
|
+
delete existingWebsites[name];
|
|
4106
4424
|
} else changeSet.creates.push({
|
|
4107
4425
|
name,
|
|
4108
4426
|
request: {
|
|
@@ -4112,11 +4430,14 @@ async function planStaticWebsite(client, workspaceId, application) {
|
|
|
4112
4430
|
description: config.description || "",
|
|
4113
4431
|
allowedIpAddresses: config.allowedIpAddresses || []
|
|
4114
4432
|
}
|
|
4115
|
-
}
|
|
4433
|
+
},
|
|
4434
|
+
metaRequest
|
|
4116
4435
|
});
|
|
4117
4436
|
}
|
|
4118
|
-
|
|
4119
|
-
|
|
4437
|
+
Object.entries(existingWebsites).forEach(([name]) => {
|
|
4438
|
+
const label = existingWebsites[name]?.label;
|
|
4439
|
+
if (label && label !== application.name) resourceOwners.add(label);
|
|
4440
|
+
if (label === application.name) changeSet.deletes.push({
|
|
4120
4441
|
name,
|
|
4121
4442
|
request: {
|
|
4122
4443
|
workspaceId,
|
|
@@ -4125,30 +4446,39 @@ async function planStaticWebsite(client, workspaceId, application) {
|
|
|
4125
4446
|
});
|
|
4126
4447
|
});
|
|
4127
4448
|
changeSet.print();
|
|
4128
|
-
return
|
|
4449
|
+
return {
|
|
4450
|
+
changeSet,
|
|
4451
|
+
conflicts,
|
|
4452
|
+
unmanaged,
|
|
4453
|
+
resourceOwners
|
|
4454
|
+
};
|
|
4129
4455
|
}
|
|
4130
4456
|
|
|
4131
4457
|
//#endregion
|
|
4132
4458
|
//#region src/cli/apply/services/tailordb.ts
|
|
4133
|
-
async function applyTailorDB(client,
|
|
4459
|
+
async function applyTailorDB(client, result, phase = "create-update") {
|
|
4460
|
+
const { changeSet } = result;
|
|
4134
4461
|
if (phase === "create-update") {
|
|
4135
|
-
await Promise.all(changeSet.service.creates.map((create) =>
|
|
4462
|
+
await Promise.all([...changeSet.service.creates.map(async (create) => {
|
|
4463
|
+
await client.createTailorDBService(create.request);
|
|
4464
|
+
await client.setMetadata(create.metaRequest);
|
|
4465
|
+
}), ...changeSet.service.updates.map((update) => client.setMetadata(update.metaRequest))]);
|
|
4136
4466
|
await Promise.all([...changeSet.type.creates.map((create) => client.createTailorDBType(create.request)), ...changeSet.type.updates.map((update) => client.updateTailorDBType(update.request))]);
|
|
4137
4467
|
await Promise.all([...changeSet.gqlPermission.creates.map((create) => client.createTailorDBGQLPermission(create.request)), ...changeSet.gqlPermission.updates.map((update) => client.updateTailorDBGQLPermission(update.request))]);
|
|
4138
4468
|
} else if (phase === "delete") {
|
|
4139
|
-
await Promise.all(changeSet.gqlPermission.deletes.
|
|
4140
|
-
await Promise.all(changeSet.type.deletes.
|
|
4469
|
+
await Promise.all(changeSet.gqlPermission.deletes.map((del) => client.deleteTailorDBGQLPermission(del.request)));
|
|
4470
|
+
await Promise.all(changeSet.type.deletes.map((del) => client.deleteTailorDBType(del.request)));
|
|
4141
4471
|
await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
|
|
4142
4472
|
}
|
|
4143
4473
|
}
|
|
4144
|
-
async function planTailorDB(client, workspaceId, application) {
|
|
4474
|
+
async function planTailorDB({ client, workspaceId, application }) {
|
|
4145
4475
|
const tailordbs = [];
|
|
4146
|
-
for (const
|
|
4476
|
+
for (const tailordb of application.tailorDBServices) {
|
|
4147
4477
|
await tailordb.loadTypes();
|
|
4148
4478
|
tailordbs.push(tailordb);
|
|
4149
4479
|
}
|
|
4150
4480
|
const executors = Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
4151
|
-
const serviceChangeSet = await planServices(client, workspaceId, tailordbs);
|
|
4481
|
+
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices(client, workspaceId, application.name, tailordbs);
|
|
4152
4482
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
4153
4483
|
const typeChangeSet = await planTypes(client, workspaceId, tailordbs, executors, deletedServices);
|
|
4154
4484
|
const gqlPermissionChangeSet = await planGqlPermissions(client, workspaceId, tailordbs, deletedServices);
|
|
@@ -4156,14 +4486,25 @@ async function planTailorDB(client, workspaceId, application) {
|
|
|
4156
4486
|
typeChangeSet.print();
|
|
4157
4487
|
gqlPermissionChangeSet.print();
|
|
4158
4488
|
return {
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4489
|
+
changeSet: {
|
|
4490
|
+
service: serviceChangeSet,
|
|
4491
|
+
type: typeChangeSet,
|
|
4492
|
+
gqlPermission: gqlPermissionChangeSet
|
|
4493
|
+
},
|
|
4494
|
+
conflicts,
|
|
4495
|
+
unmanaged,
|
|
4496
|
+
resourceOwners
|
|
4162
4497
|
};
|
|
4163
4498
|
}
|
|
4164
|
-
|
|
4499
|
+
function trn(workspaceId, name) {
|
|
4500
|
+
return `${trnPrefix(workspaceId)}:tailordb:${name}`;
|
|
4501
|
+
}
|
|
4502
|
+
async function planServices(client, workspaceId, appName, tailordbs) {
|
|
4165
4503
|
const changeSet = new ChangeSet("TailorDB services");
|
|
4166
|
-
const
|
|
4504
|
+
const conflicts = [];
|
|
4505
|
+
const unmanaged = [];
|
|
4506
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
4507
|
+
const withoutLabel = await fetchAll(async (pageToken) => {
|
|
4167
4508
|
try {
|
|
4168
4509
|
const { tailordbServices, nextPageToken } = await client.listTailorDBServices({
|
|
4169
4510
|
workspaceId,
|
|
@@ -4175,24 +4516,47 @@ async function planServices(client, workspaceId, tailordbs) {
|
|
|
4175
4516
|
throw error;
|
|
4176
4517
|
}
|
|
4177
4518
|
});
|
|
4178
|
-
const
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
}
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4519
|
+
const existingServices = {};
|
|
4520
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
4521
|
+
if (!resource.namespace?.name) return;
|
|
4522
|
+
const { metadata } = await client.getMetadata({ trn: trn(workspaceId, resource.namespace.name) });
|
|
4523
|
+
existingServices[resource.namespace.name] = {
|
|
4524
|
+
resource,
|
|
4525
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
4526
|
+
};
|
|
4527
|
+
}));
|
|
4528
|
+
for (const tailordb of tailordbs) {
|
|
4529
|
+
const existing = existingServices[tailordb.namespace];
|
|
4530
|
+
const metaRequest = await buildMetaRequest(trn(workspaceId, tailordb.namespace), appName);
|
|
4531
|
+
if (existing) {
|
|
4532
|
+
if (!existing.label) unmanaged.push({
|
|
4533
|
+
resourceType: "TailorDB service",
|
|
4534
|
+
resourceName: tailordb.namespace
|
|
4535
|
+
});
|
|
4536
|
+
else if (existing.label !== appName) conflicts.push({
|
|
4537
|
+
resourceType: "TailorDB service",
|
|
4538
|
+
resourceName: tailordb.namespace,
|
|
4539
|
+
currentOwner: existing.label
|
|
4540
|
+
});
|
|
4541
|
+
changeSet.updates.push({
|
|
4542
|
+
name: tailordb.namespace,
|
|
4543
|
+
metaRequest
|
|
4544
|
+
});
|
|
4545
|
+
delete existingServices[tailordb.namespace];
|
|
4546
|
+
} else changeSet.creates.push({
|
|
4547
|
+
name: tailordb.namespace,
|
|
4548
|
+
request: {
|
|
4549
|
+
workspaceId,
|
|
4550
|
+
namespaceName: tailordb.namespace,
|
|
4551
|
+
defaultTimezone: "UTC"
|
|
4552
|
+
},
|
|
4553
|
+
metaRequest
|
|
4554
|
+
});
|
|
4555
|
+
}
|
|
4556
|
+
Object.entries(existingServices).forEach(([namespaceName]) => {
|
|
4557
|
+
const label = existingServices[namespaceName]?.label;
|
|
4558
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
4559
|
+
if (label === appName) changeSet.deletes.push({
|
|
4196
4560
|
name: namespaceName,
|
|
4197
4561
|
request: {
|
|
4198
4562
|
workspaceId,
|
|
@@ -4200,7 +4564,12 @@ async function planServices(client, workspaceId, tailordbs) {
|
|
|
4200
4564
|
}
|
|
4201
4565
|
});
|
|
4202
4566
|
});
|
|
4203
|
-
return
|
|
4567
|
+
return {
|
|
4568
|
+
changeSet,
|
|
4569
|
+
conflicts,
|
|
4570
|
+
unmanaged,
|
|
4571
|
+
resourceOwners
|
|
4572
|
+
};
|
|
4204
4573
|
}
|
|
4205
4574
|
async function planTypes(client, workspaceId, tailordbs, executors, deletedServices) {
|
|
4206
4575
|
const changeSet = new ChangeSet("TailorDB types");
|
|
@@ -4249,7 +4618,6 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
4249
4618
|
}
|
|
4250
4619
|
existingNameSet.forEach((name) => {
|
|
4251
4620
|
changeSet.deletes.push({
|
|
4252
|
-
tag: "type-deleted",
|
|
4253
4621
|
name,
|
|
4254
4622
|
request: {
|
|
4255
4623
|
workspaceId,
|
|
@@ -4261,8 +4629,12 @@ async function planTypes(client, workspaceId, tailordbs, executors, deletedServi
|
|
|
4261
4629
|
}
|
|
4262
4630
|
for (const namespaceName of deletedServices) (await fetchTypes(namespaceName)).forEach((typ) => {
|
|
4263
4631
|
changeSet.deletes.push({
|
|
4264
|
-
|
|
4265
|
-
|
|
4632
|
+
name: typ.name,
|
|
4633
|
+
request: {
|
|
4634
|
+
workspaceId,
|
|
4635
|
+
namespaceName,
|
|
4636
|
+
tailordbTypeName: typ.name
|
|
4637
|
+
}
|
|
4266
4638
|
});
|
|
4267
4639
|
});
|
|
4268
4640
|
return changeSet;
|
|
@@ -4520,7 +4892,6 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
4520
4892
|
}
|
|
4521
4893
|
existingNameSet.forEach((name) => {
|
|
4522
4894
|
changeSet.deletes.push({
|
|
4523
|
-
tag: "gql-permission-deleted",
|
|
4524
4895
|
name,
|
|
4525
4896
|
request: {
|
|
4526
4897
|
workspaceId,
|
|
@@ -4532,8 +4903,12 @@ async function planGqlPermissions(client, workspaceId, tailordbs, deletedService
|
|
|
4532
4903
|
}
|
|
4533
4904
|
for (const namespaceName of deletedServices) (await fetchGqlPermissions(namespaceName)).forEach((gqlPermission) => {
|
|
4534
4905
|
changeSet.deletes.push({
|
|
4535
|
-
|
|
4536
|
-
|
|
4906
|
+
name: gqlPermission.typeName,
|
|
4907
|
+
request: {
|
|
4908
|
+
workspaceId,
|
|
4909
|
+
namespaceName,
|
|
4910
|
+
typeName: gqlPermission.typeName
|
|
4911
|
+
}
|
|
4537
4912
|
});
|
|
4538
4913
|
});
|
|
4539
4914
|
return changeSet;
|
|
@@ -4628,6 +5003,7 @@ async function apply(options) {
|
|
|
4628
5003
|
const configPath = loadConfigPath(options?.configPath);
|
|
4629
5004
|
const { config } = await loadConfig(configPath);
|
|
4630
5005
|
const dryRun = options?.dryRun ?? false;
|
|
5006
|
+
const yes = options?.yes ?? false;
|
|
4631
5007
|
const buildOnly = options?.buildOnly ?? false;
|
|
4632
5008
|
await generateUserTypes(config, configPath);
|
|
4633
5009
|
const application = defineApplication(config);
|
|
@@ -4643,13 +5019,66 @@ async function apply(options) {
|
|
|
4643
5019
|
workspaceId: options?.workspaceId,
|
|
4644
5020
|
profile: options?.profile
|
|
4645
5021
|
});
|
|
4646
|
-
const
|
|
4647
|
-
const
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
const
|
|
4651
|
-
|
|
4652
|
-
|
|
5022
|
+
for (const tailordb of application.tailorDBServices) await tailordb.loadTypes();
|
|
5023
|
+
for (const pipeline$1 of application.resolverServices) await pipeline$1.loadResolvers();
|
|
5024
|
+
if (application.executorService) await application.executorService.loadExecutors();
|
|
5025
|
+
console.log("");
|
|
5026
|
+
const ctx = {
|
|
5027
|
+
client,
|
|
5028
|
+
workspaceId,
|
|
5029
|
+
application
|
|
5030
|
+
};
|
|
5031
|
+
const tailorDB = await planTailorDB(ctx);
|
|
5032
|
+
const staticWebsite = await planStaticWebsite(ctx);
|
|
5033
|
+
const idp = await planIdP(ctx);
|
|
5034
|
+
const auth = await planAuth(ctx);
|
|
5035
|
+
const pipeline = await planPipeline(ctx);
|
|
5036
|
+
const app = await planApplication(ctx);
|
|
5037
|
+
const executor = await planExecutor(ctx);
|
|
5038
|
+
const allConflicts = [
|
|
5039
|
+
...tailorDB.conflicts,
|
|
5040
|
+
...staticWebsite.conflicts,
|
|
5041
|
+
...idp.conflicts,
|
|
5042
|
+
...auth.conflicts,
|
|
5043
|
+
...pipeline.conflicts,
|
|
5044
|
+
...executor.conflicts
|
|
5045
|
+
];
|
|
5046
|
+
await confirmOwnerConflict(allConflicts, application.name, yes);
|
|
5047
|
+
const allUnmanaged = [
|
|
5048
|
+
...tailorDB.unmanaged,
|
|
5049
|
+
...staticWebsite.unmanaged,
|
|
5050
|
+
...idp.unmanaged,
|
|
5051
|
+
...auth.unmanaged,
|
|
5052
|
+
...pipeline.unmanaged,
|
|
5053
|
+
...executor.unmanaged
|
|
5054
|
+
];
|
|
5055
|
+
await confirmUnmanagedResources(allUnmanaged, application.name, yes);
|
|
5056
|
+
const importantDeletions = [];
|
|
5057
|
+
for (const del of tailorDB.changeSet.type.deletes) importantDeletions.push({
|
|
5058
|
+
resourceType: "TailorDB type",
|
|
5059
|
+
resourceName: del.name
|
|
5060
|
+
});
|
|
5061
|
+
for (const del of staticWebsite.changeSet.deletes) importantDeletions.push({
|
|
5062
|
+
resourceType: "StaticWebsite",
|
|
5063
|
+
resourceName: del.name
|
|
5064
|
+
});
|
|
5065
|
+
await confirmImportantResourceDeletion(importantDeletions, yes);
|
|
5066
|
+
const resourceOwners = new Set([
|
|
5067
|
+
...tailorDB.resourceOwners,
|
|
5068
|
+
...staticWebsite.resourceOwners,
|
|
5069
|
+
...idp.resourceOwners,
|
|
5070
|
+
...auth.resourceOwners,
|
|
5071
|
+
...pipeline.resourceOwners,
|
|
5072
|
+
...executor.resourceOwners
|
|
5073
|
+
]);
|
|
5074
|
+
const emptyApps = [...new Set(allConflicts.map((c) => c.currentOwner))].filter((owner) => !resourceOwners.has(owner));
|
|
5075
|
+
for (const emptyApp of emptyApps) app.deletes.push({
|
|
5076
|
+
name: emptyApp,
|
|
5077
|
+
request: {
|
|
5078
|
+
workspaceId,
|
|
5079
|
+
applicationName: emptyApp
|
|
5080
|
+
}
|
|
5081
|
+
});
|
|
4653
5082
|
if (dryRun) {
|
|
4654
5083
|
console.log("Dry run enabled. No changes applied.");
|
|
4655
5084
|
return;
|
|
@@ -4724,6 +5153,11 @@ const applyCommand = defineCommand({
|
|
|
4724
5153
|
type: "boolean",
|
|
4725
5154
|
description: "Run the command without making any changes",
|
|
4726
5155
|
alias: "d"
|
|
5156
|
+
},
|
|
5157
|
+
yes: {
|
|
5158
|
+
type: "boolean",
|
|
5159
|
+
description: "Skip all confirmation prompts",
|
|
5160
|
+
alias: "y"
|
|
4727
5161
|
}
|
|
4728
5162
|
},
|
|
4729
5163
|
run: withCommonArgs(async (args) => {
|
|
@@ -4731,7 +5165,8 @@ const applyCommand = defineCommand({
|
|
|
4731
5165
|
workspaceId: args["workspace-id"],
|
|
4732
5166
|
profile: args.profile,
|
|
4733
5167
|
configPath: args.config,
|
|
4734
|
-
dryRun: args.dryRun
|
|
5168
|
+
dryRun: args.dryRun,
|
|
5169
|
+
yes: args.yes
|
|
4735
5170
|
});
|
|
4736
5171
|
})
|
|
4737
5172
|
});
|
|
@@ -5855,4 +6290,4 @@ const tokenCommand = defineCommand({
|
|
|
5855
6290
|
});
|
|
5856
6291
|
|
|
5857
6292
|
//#endregion
|
|
5858
|
-
export { PATScope, apply, applyCommand, commonArgs, createCommand, deleteCommand, fetchAll, fetchLatestToken, formatArgs, generate, generateCommand, generateUserTypes, initOperatorClient, listCommand, listCommand$1, loadAccessToken, loadConfig, loadConfigPath, loadWorkspaceId, machineUserList, machineUserToken, parseFormat, printWithFormat, readPlatformConfig, show, showCommand, tokenCommand, userAgent, withCommonArgs, workspaceCreate, workspaceDelete, workspaceList, writePlatformConfig };
|
|
6293
|
+
export { PATScope, apply, applyCommand, commonArgs, createCommand, deleteCommand, fetchAll, fetchLatestToken, formatArgs, generate, generateCommand, generateUserTypes, initOperatorClient, listCommand, listCommand$1, loadAccessToken, loadConfig, loadConfigPath, loadWorkspaceId, machineUserList, machineUserToken, parseFormat, printWithFormat, readPackageJson, readPlatformConfig, show, showCommand, tokenCommand, userAgent, withCommonArgs, workspaceCreate, workspaceDelete, workspaceList, writePlatformConfig };
|