great 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -40
- package/dist/clone/index.d.ts +2 -2
- package/dist/clone/index.js.map +1 -1
- package/dist/deploy/index.d.ts +2 -2
- package/dist/deploy/index.js.map +1 -1
- package/dist/explode/index.d.ts +2 -2
- package/dist/explode/index.js.map +1 -1
- package/dist/generated/operations.d.ts +7 -7
- package/dist/generated/schema.d.ts +122 -2
- package/dist/generated/schema.js +15 -0
- package/dist/generated/schema.js.map +1 -1
- package/dist/implode/index.d.ts +2 -2
- package/dist/implode/index.js +1 -0
- package/dist/implode/index.js.map +1 -1
- package/dist/implode/transform.d.ts +1 -0
- package/dist/implode/transform.js +16 -2
- package/dist/implode/transform.js.map +1 -1
- package/dist/import/index.d.ts +2 -2
- package/dist/import/index.js.map +1 -1
- package/dist/include/index.d.ts +2 -2
- package/dist/include/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/init/index.d.ts +2 -2
- package/dist/init/index.js +3 -3
- package/dist/init/index.js.map +1 -1
- package/dist/integrations/create.js +1 -1
- package/dist/integrations/create.js.map +1 -1
- package/dist/integrations/index.js +1 -1
- package/dist/integrations/index.js.map +1 -1
- package/dist/migrate/index.d.ts +5 -2
- package/dist/migrate/index.js +102 -4
- package/dist/migrate/index.js.map +1 -1
- package/dist/pull/index.d.ts +2 -2
- package/dist/pull/index.js.map +1 -1
- package/dist/push/index.d.ts +3 -2
- package/dist/push/index.js +133 -61
- package/dist/push/index.js.map +1 -1
- package/dist/rename/index.d.ts +2 -2
- package/dist/rename/index.js +51 -21
- package/dist/rename/index.js.map +1 -1
- package/dist/run/index.d.ts +29 -2
- package/dist/run/index.js.map +1 -1
- package/dist/status/index.d.ts +2 -2
- package/dist/status/index.js +1 -1
- package/dist/status/index.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/utils/createIntegrationFromFile.d.ts +2 -2
- package/dist/utils/createIntegrationFromFile.js.map +1 -1
- package/dist/utils/detectPullConflicts.d.ts +2 -2
- package/dist/utils/detectPullConflicts.js +9 -14
- package/dist/utils/detectPullConflicts.js.map +1 -1
- package/dist/utils/elementFiles.d.ts +18 -7
- package/dist/utils/elementFiles.js +114 -8
- package/dist/utils/elementFiles.js.map +1 -1
- package/dist/utils/fetchLocal.d.ts +4 -4
- package/dist/utils/fetchLocal.js.map +1 -1
- package/dist/utils/greatFile.d.ts +3 -3
- package/dist/utils/greatFile.js.map +1 -1
- package/dist/utils/promptForDetach.d.ts +6 -0
- package/dist/utils/promptForDetach.js +15 -0
- package/dist/utils/promptForDetach.js.map +1 -0
- package/dist/utils/resolveAccount.d.ts +2 -2
- package/dist/utils/resolveAccount.js.map +1 -1
- package/dist/utils/resolveElement.d.ts +2 -0
- package/dist/utils/resolveElement.js +8 -0
- package/dist/utils/resolveElement.js.map +1 -1
- package/dist/utils/saveIntegration.d.ts +2 -2
- package/dist/utils/saveIntegration.js +54 -30
- package/dist/utils/saveIntegration.js.map +1 -1
- package/dist/utils/serviceFile.d.ts +31 -0
- package/dist/utils/serviceFile.js +89 -0
- package/dist/utils/serviceFile.js.map +1 -0
- package/dist/utils/shadowMarker.d.ts +5 -0
- package/dist/utils/shadowMarker.js +16 -0
- package/dist/utils/shadowMarker.js.map +1 -0
- package/dist/utils/writeShadowElement.d.ts +2 -3
- package/dist/utils/writeShadowElement.js +20 -19
- package/dist/utils/writeShadowElement.js.map +1 -1
- package/dist/values/get.d.ts +2 -2
- package/dist/values/get.js.map +1 -1
- package/dist/values/list.d.ts +2 -2
- package/dist/values/list.js.map +1 -1
- package/dist/values/set.d.ts +2 -2
- package/dist/values/set.js.map +1 -1
- package/dist/values/unset.d.ts +2 -2
- package/dist/values/unset.js.map +1 -1
- package/package.json +16 -17
- package/quality.toml +4 -0
package/dist/migrate/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
+
import { camelCase } from 'change-case';
|
|
4
5
|
import parseJson from '../utils/parseJson.js';
|
|
5
6
|
import hashContent from '../utils/hashContent.js';
|
|
6
7
|
import { currentIntegrationKey } from '../utils/fetchLocal.js';
|
|
7
|
-
import { ELEMENT_FOLDERS, elementKeyFromFileName, } from '../utils/elementFiles.js';
|
|
8
|
+
import { ELEMENT_FOLDERS, elementKeyFromFileName, readElementFolder, } from '../utils/elementFiles.js';
|
|
9
|
+
import { ENDPOINTS_FOLDER, SERVICES_FOLDER, classifyEndpoints, mergeServiceFile, } from '../utils/serviceFile.js';
|
|
10
|
+
import { SHADOW_MARKER, isShadowMarker } from '../utils/shadowMarker.js';
|
|
8
11
|
import { readGreatFile, writeGreatFile, getElementRecord, setElementRecord, } from '../utils/greatFile.js';
|
|
12
|
+
const MAX_KEY_LENGTH = 50;
|
|
9
13
|
const hasMetaProps = (data) => '__id' in data || '__key' in data || '__timestamp' in data;
|
|
10
14
|
function migrateIntegrationFile(great, log, fsImpl) {
|
|
11
15
|
const filePath = 'integration.json';
|
|
@@ -77,7 +81,95 @@ function migrateElementFiles(great, fsImpl) {
|
|
|
77
81
|
}
|
|
78
82
|
return count;
|
|
79
83
|
}
|
|
80
|
-
|
|
84
|
+
function collectEndpointKeys(services, great, fsImpl) {
|
|
85
|
+
const keys = new Set();
|
|
86
|
+
for (const { key } of readElementFolder(ENDPOINTS_FOLDER, undefined, fsImpl)) {
|
|
87
|
+
keys.add(key);
|
|
88
|
+
}
|
|
89
|
+
for (const recordKey of Object.keys(great.elements)) {
|
|
90
|
+
if (recordKey.startsWith(`${ENDPOINTS_FOLDER}/`)) {
|
|
91
|
+
keys.add(recordKey.slice(ENDPOINTS_FOLDER.length + 1));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const { data } of services) {
|
|
95
|
+
if (Array.isArray(data.endpoints)) {
|
|
96
|
+
for (const entry of data.endpoints) {
|
|
97
|
+
if (typeof entry === 'string') {
|
|
98
|
+
keys.add(entry);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return keys;
|
|
104
|
+
}
|
|
105
|
+
function endpointKeyFor(serviceKey, endpoint, index, prefix) {
|
|
106
|
+
const base = typeof endpoint.id === 'string' && endpoint.id
|
|
107
|
+
? endpoint.id
|
|
108
|
+
: `endpoint${index + 1}`;
|
|
109
|
+
const key = prefix
|
|
110
|
+
? `${camelCase(serviceKey)}-${camelCase(base)}`
|
|
111
|
+
: camelCase(base);
|
|
112
|
+
return key.slice(0, MAX_KEY_LENGTH);
|
|
113
|
+
}
|
|
114
|
+
function uniqueKey(key, existing) {
|
|
115
|
+
if (!existing.has(key)) {
|
|
116
|
+
return key;
|
|
117
|
+
}
|
|
118
|
+
for (let n = 2;; n++) {
|
|
119
|
+
const suffix = String(n);
|
|
120
|
+
const candidate = `${key.slice(0, MAX_KEY_LENGTH - suffix.length)}${suffix}`;
|
|
121
|
+
if (!existing.has(candidate)) {
|
|
122
|
+
return candidate;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
127
|
+
function extractEndpoints(serviceKey, endpoints, existingKeys, prefix, fsImpl) {
|
|
128
|
+
const keys = [];
|
|
129
|
+
let extracted = 0;
|
|
130
|
+
endpoints.forEach((entry, index) => {
|
|
131
|
+
if (typeof entry === 'string') {
|
|
132
|
+
keys.push(entry);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!isObject(entry)) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const key = uniqueKey(endpointKeyFor(serviceKey, entry, index, prefix), existingKeys);
|
|
139
|
+
existingKeys.add(key);
|
|
140
|
+
const { id: _id, ...content } = entry;
|
|
141
|
+
fsImpl.writeFileSync(path.join(ENDPOINTS_FOLDER, `${key}.json`), JSON.stringify(content, undefined, 2));
|
|
142
|
+
keys.push(key);
|
|
143
|
+
extracted++;
|
|
144
|
+
});
|
|
145
|
+
return { keys, extracted };
|
|
146
|
+
}
|
|
147
|
+
function migrateInlineEndpoints(great, options, log, fsImpl) {
|
|
148
|
+
const services = readElementFolder(SERVICES_FOLDER, undefined, fsImpl);
|
|
149
|
+
const existingKeys = collectEndpointKeys(services, great, fsImpl);
|
|
150
|
+
const prefix = options.prefix !== false;
|
|
151
|
+
let count = 0;
|
|
152
|
+
for (const { key, filePath, data } of services) {
|
|
153
|
+
const kind = classifyEndpoints(data.endpoints);
|
|
154
|
+
if (kind !== 'inline' && kind !== 'mixed') {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (getElementRecord(great, SERVICES_FOLDER, key)?.source) {
|
|
158
|
+
log(chalk.yellow(`Skipping ${filePath}: it is a shadow element, so its inline endpoints belong to the source`));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (!fsImpl.existsSync(ENDPOINTS_FOLDER)) {
|
|
162
|
+
fsImpl.mkdirSync(ENDPOINTS_FOLDER, { recursive: true });
|
|
163
|
+
}
|
|
164
|
+
const { keys, extracted } = extractEndpoints(key, data.endpoints, existingKeys, prefix, fsImpl);
|
|
165
|
+
const { [SHADOW_MARKER]: marker, endpoints: _endpoints, ...service } = data;
|
|
166
|
+
fsImpl.writeFileSync(filePath, JSON.stringify(mergeServiceFile({ service, list: { endpoints: keys } }, isShadowMarker(marker) ? marker : undefined), undefined, 2));
|
|
167
|
+
log(` ${filePath}: ${extracted} endpoint(s) extracted`);
|
|
168
|
+
count += extracted;
|
|
169
|
+
}
|
|
170
|
+
return count;
|
|
171
|
+
}
|
|
172
|
+
export const action = (log, fsImpl = fs) => async function migrate(options = {}) {
|
|
81
173
|
if (!fsImpl.existsSync('integration.json')) {
|
|
82
174
|
log(chalk.red('No integration.json found in this directory'));
|
|
83
175
|
return;
|
|
@@ -85,10 +177,15 @@ export const action = (log, fsImpl = fs) => async function migrate() {
|
|
|
85
177
|
const great = readGreatFile(undefined, fsImpl);
|
|
86
178
|
const integrationMigrated = migrateIntegrationFile(great, log, fsImpl);
|
|
87
179
|
const elementCount = migrateElementFiles(great, fsImpl);
|
|
180
|
+
const endpointCount = migrateInlineEndpoints(great, options, log, fsImpl);
|
|
88
181
|
writeGreatFile(great, undefined, fsImpl);
|
|
89
|
-
if (integrationMigrated || elementCount > 0) {
|
|
182
|
+
if (integrationMigrated || elementCount > 0 || endpointCount > 0) {
|
|
90
183
|
log(chalk.green('✓ Migrated to .great.json'));
|
|
91
184
|
log(` Elements migrated: ${elementCount}`);
|
|
185
|
+
log(` Endpoints extracted: ${endpointCount}`);
|
|
186
|
+
if (endpointCount > 0) {
|
|
187
|
+
log(`Run ${chalk.bold('great push')} to create the endpoints in Integreat`);
|
|
188
|
+
}
|
|
92
189
|
}
|
|
93
190
|
else {
|
|
94
191
|
log(chalk.green('Already migrated — nothing to do'));
|
|
@@ -96,6 +193,7 @@ export const action = (log, fsImpl = fs) => async function migrate() {
|
|
|
96
193
|
};
|
|
97
194
|
export default (program) => program
|
|
98
195
|
.command('migrate')
|
|
99
|
-
.description('Migrate
|
|
196
|
+
.description('Migrate the workspace to the newest layout: sync bookkeeping in .great.json and endpoints as separate elements')
|
|
197
|
+
.option('--no-prefix', 'do not prefix extracted endpoint keys with the service key')
|
|
100
198
|
.action(action(console.log));
|
|
101
199
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrate/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,SAAS,MAAM,uBAAuB,CAAA;AAC7C,OAAO,WAAW,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,EACL,eAAe,EACf,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrate/index.ts"],"names":[],"mappings":"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"}
|
package/dist/pull/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import Conf from 'conf';
|
|
3
2
|
import { type GraphQLRequestClient } from '../utils/graphqlClient.js';
|
|
4
3
|
import type { ConfigSchema } from '../utils/config.js';
|
|
5
4
|
import type { Command } from 'commander';
|
|
6
|
-
|
|
5
|
+
import type { GreatFs } from '../types.js';
|
|
6
|
+
export declare const action: (log: (message: string) => void, apiToken?: string, client?: GraphQLRequestClient, fsImpl?: GreatFs, config?: Conf<ConfigSchema>) => (options?: {
|
|
7
7
|
force?: boolean;
|
|
8
8
|
}) => Promise<void>;
|
|
9
9
|
declare const _default: (program: Command, apiToken?: string) => Command;
|
package/dist/pull/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pull/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pull/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,eAAe,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAA6B,MAAM,2BAA2B,CAAA;AAChF,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,mBAAmB,MAAM,iCAAiC,CAAA;AAMjE,SAAS,eAAe,CACtB,SAAyB,EACzB,GAA8B;IAE9B,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAA;IAE/C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QACvC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,GAAG,CACD,iDAAiD,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,qBAAqB,CACvG,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,GAA8B,EAC9B,QAAiB,EACjB,MAA6B,EAC7B,MAAgB,EAChB,MAA2B,EAC3B,EAAE,CACF,KAAK,UAAU,eAAe,CAAC,UAA+B,EAAE;IAE9D,MAAM,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC,CAAA;QACpD,GAAG,CACD,OAAO,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,0CAA0C,CAC5F,CAAA;QACD,OAAM;IACR,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACzD,MAAM,WAAW,GAAG,MAAM,0BAA0B,CAAC,aAAa,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;IAC5E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAM;IACR,CAAC;IAID,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QACnD,MAAM,SAAS,GAAG,mBAAmB,CACnC,WAAW,CAAC,MAAM,EAClB,UAAU,EACV,SAAS,EACT,MAAM,CACP,CAAA;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;YAC/B,OAAM;QACR,CAAC;IACH,CAAC;IAED,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;AACrE,CAAC,CAAA;AAEH,eAAe,CAAC,OAAgB,EAAE,QAAiB,EAAE,EAAE,CACrD,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,aAAa,EAAE,gDAAgD,CAAC;KACvE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA"}
|
package/dist/push/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import Conf from 'conf';
|
|
2
|
+
import { promptForDetach } from '../utils/promptForDetach.js';
|
|
3
3
|
import { type GraphQLRequestClient } from '../utils/graphqlClient.js';
|
|
4
4
|
import type { ConfigSchema } from '../utils/config.js';
|
|
5
5
|
import { promptForValueSetting } from '../utils/promptForValue.js';
|
|
6
6
|
import type { Command } from 'commander';
|
|
7
|
-
|
|
7
|
+
import type { GreatFs } from '../types.js';
|
|
8
|
+
export declare const action: (log: (message: string) => void, apiToken?: string, client?: GraphQLRequestClient, fsImpl?: GreatFs, config?: Conf<ConfigSchema>, promptForValueSettingFn?: typeof promptForValueSetting, promptForDetachFn?: typeof promptForDetach) => (options?: {
|
|
8
9
|
account?: string;
|
|
9
10
|
}) => Promise<void>;
|
|
10
11
|
declare const _default: (program: Command, apiToken?: string) => Command;
|
package/dist/push/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import parseJson from '../utils/parseJson.js';
|
|
4
3
|
import { sentenceCase } from 'change-case';
|
|
5
4
|
import { fetchIntegrationFromFile } from '../utils/fetchLocal.js';
|
|
6
5
|
import { readGreatFile, writeGreatFile, getElementRecord, setElementRecord, removeElementRecordById, sameProvenance, } from '../utils/greatFile.js';
|
|
7
|
-
import {
|
|
6
|
+
import { readWorkspaceElements, writeElementFile, folderToElementType, } from '../utils/elementFiles.js';
|
|
7
|
+
import { ENDPOINT_LISTS_FOLDER, validateEndpointReferences, } from '../utils/serviceFile.js';
|
|
8
|
+
import { promptForDetach } from '../utils/promptForDetach.js';
|
|
9
|
+
import { fetchElementById } from '../utils/resolveElement.js';
|
|
8
10
|
import createIntegrationFromFile from '../utils/createIntegrationFromFile.js';
|
|
9
11
|
import { typeToFolder } from '../utils/saveIntegration.js';
|
|
10
12
|
import { getClient } from '../utils/graphqlClient.js';
|
|
11
|
-
import { getGraphQLErrorMessage, handleGraphQLError, } from '../utils/graphqlError.js';
|
|
13
|
+
import { getGraphQLErrorMessage, handleGraphQLError, isNotFoundError, } from '../utils/graphqlError.js';
|
|
12
14
|
import hashContent from '../utils/hashContent.js';
|
|
13
15
|
import { VALID_VALUE_TYPES, isValidValueElementType, } from '../utils/valueTypes.js';
|
|
14
16
|
import { setValueForElement } from '../values/set.js';
|
|
15
17
|
import { promptForValueSetting } from '../utils/promptForValue.js';
|
|
16
|
-
import { SHADOW_MARKER } from '../utils/writeShadowElement.js';
|
|
17
18
|
import resolveIntegrationType from '../utils/integrationType.js';
|
|
18
19
|
import { ElementType } from '../generated/schema.js';
|
|
19
20
|
import { gql } from 'graphql-tag';
|
|
@@ -158,14 +159,39 @@ const SetSecretRefMutationDocument = gql `
|
|
|
158
159
|
setSecretRef(id: $id, secretRef: $secretRef)
|
|
159
160
|
}
|
|
160
161
|
`;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
const readLocalElements = (fsImpl) => readWorkspaceElements(undefined, fsImpl);
|
|
163
|
+
const isEndpointList = (element) => element.folder === ENDPOINT_LISTS_FOLDER;
|
|
164
|
+
const hasShadowContentChanged = (local) => local.hash !== undefined && hashContent(local.data) !== local.hash;
|
|
165
|
+
function compareShadow(local, remote, source) {
|
|
166
|
+
const localName = local.data.name || '';
|
|
167
|
+
const localDesc = local.data.description || '';
|
|
168
|
+
const isList = isEndpointList(local);
|
|
169
|
+
const hasNameChanged = !isList && localName !== (remote.name || '');
|
|
170
|
+
const hasDescriptionChanged = !isList && localDesc !== (remote.description || '');
|
|
171
|
+
const hasPinChanged = (source.timestamp ?? null) !== (remote.sourceTimestamp ?? null);
|
|
172
|
+
const hasProvenanceChanged = !sameProvenance(local.provenance, remote.provenance);
|
|
173
|
+
const hasRemoteMoved = local.timestamp !== remote.contentCreatedAt;
|
|
174
|
+
if (hasShadowContentChanged(local)) {
|
|
175
|
+
return hasRemoteMoved
|
|
176
|
+
? {
|
|
177
|
+
category: 'conflict',
|
|
178
|
+
reason: ' Shadow content changed locally and shadow changed remotely',
|
|
179
|
+
}
|
|
180
|
+
: { category: 'detach' };
|
|
181
|
+
}
|
|
182
|
+
if (!hasNameChanged &&
|
|
183
|
+
!hasDescriptionChanged &&
|
|
184
|
+
!hasPinChanged &&
|
|
185
|
+
!hasProvenanceChanged) {
|
|
186
|
+
return { category: 'unchanged' };
|
|
187
|
+
}
|
|
188
|
+
if (hasPinChanged && hasRemoteMoved) {
|
|
189
|
+
return {
|
|
190
|
+
category: 'conflict',
|
|
191
|
+
reason: ' Shadow pin changed both local and remote',
|
|
192
|
+
};
|
|
167
193
|
}
|
|
168
|
-
return
|
|
194
|
+
return { category: 'update' };
|
|
169
195
|
}
|
|
170
196
|
function compareLocalAndRemote(local, remote) {
|
|
171
197
|
if (!remote) {
|
|
@@ -174,27 +200,12 @@ function compareLocalAndRemote(local, remote) {
|
|
|
174
200
|
reason: 'Element exists locally with an id but not found in Integreat',
|
|
175
201
|
};
|
|
176
202
|
}
|
|
177
|
-
const localName = local.data.name || '';
|
|
178
|
-
const localDesc = local.data.description || '';
|
|
179
203
|
if (local.source) {
|
|
180
|
-
|
|
181
|
-
const hasDescriptionChanged = localDesc !== (remote.description || '');
|
|
182
|
-
const hasPinChanged = (local.source.timestamp ?? null) !== (remote.sourceTimestamp ?? null);
|
|
183
|
-
const hasProvenanceChanged = !sameProvenance(local.provenance, remote.provenance);
|
|
184
|
-
if (!hasNameChanged &&
|
|
185
|
-
!hasDescriptionChanged &&
|
|
186
|
-
!hasPinChanged &&
|
|
187
|
-
!hasProvenanceChanged) {
|
|
188
|
-
return { category: 'unchanged' };
|
|
189
|
-
}
|
|
190
|
-
if (hasPinChanged && local.timestamp !== remote.contentCreatedAt) {
|
|
191
|
-
return {
|
|
192
|
-
category: 'conflict',
|
|
193
|
-
reason: ' Shadow pin changed both local and remote',
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return { category: 'update' };
|
|
204
|
+
return compareShadow(local, remote, local.source);
|
|
197
205
|
}
|
|
206
|
+
const localName = local.data.name || '';
|
|
207
|
+
const localDesc = local.data.description || '';
|
|
208
|
+
const isList = isEndpointList(local);
|
|
198
209
|
const localChecksum = hashContent(local.data);
|
|
199
210
|
const localTimestamp = local.timestamp ? new Date(local.timestamp) : undefined;
|
|
200
211
|
const remoteChecksum = remote.checksum || '';
|
|
@@ -204,8 +215,8 @@ function compareLocalAndRemote(local, remote) {
|
|
|
204
215
|
? new Date(remote.createdAt)
|
|
205
216
|
: undefined;
|
|
206
217
|
const hasContentChanged = localChecksum !== remoteChecksum;
|
|
207
|
-
const hasNameChanged = localName !== remoteName;
|
|
208
|
-
const hasDescriptionChanged = localDesc !== remoteDesc;
|
|
218
|
+
const hasNameChanged = !isList && localName !== remoteName;
|
|
219
|
+
const hasDescriptionChanged = !isList && localDesc !== remoteDesc;
|
|
209
220
|
if (!hasContentChanged && !hasNameChanged && !hasDescriptionChanged) {
|
|
210
221
|
return { category: 'unchanged' };
|
|
211
222
|
}
|
|
@@ -234,6 +245,7 @@ function categorizeElements(localElements, remoteElementsMap) {
|
|
|
234
245
|
const toCreate = [];
|
|
235
246
|
const toInclude = [];
|
|
236
247
|
const toUpdate = [];
|
|
248
|
+
const toDetach = [];
|
|
237
249
|
const toDelete = [];
|
|
238
250
|
const conflicts = [];
|
|
239
251
|
const localElementIds = new Set();
|
|
@@ -256,13 +268,18 @@ function categorizeElements(localElements, remoteElementsMap) {
|
|
|
256
268
|
else if (result.category === 'update') {
|
|
257
269
|
toUpdate.push({ ...local, remoteId: remote?.id });
|
|
258
270
|
}
|
|
271
|
+
else if (result.category === 'detach') {
|
|
272
|
+
toDetach.push({ ...local, remoteId: remote?.id });
|
|
273
|
+
}
|
|
259
274
|
}
|
|
260
275
|
for (const [id, remoteLement] of remoteElementsMap) {
|
|
261
276
|
if (!localElementIds.has(id)) {
|
|
262
277
|
toDelete.push(remoteLement);
|
|
263
278
|
}
|
|
264
279
|
}
|
|
265
|
-
|
|
280
|
+
toDelete.sort((a, b) => Number(b.folder === ENDPOINT_LISTS_FOLDER) -
|
|
281
|
+
Number(a.folder === ENDPOINT_LISTS_FOLDER));
|
|
282
|
+
return { toCreate, toInclude, toUpdate, toDetach, toDelete, conflicts };
|
|
266
283
|
}
|
|
267
284
|
const prepareContentForApi = ({ name, description, ...content }, elementType) => {
|
|
268
285
|
if (elementType === ElementType.Value) {
|
|
@@ -283,7 +300,9 @@ const prepareContentForApi = ({ name, description, ...content }, elementType) =>
|
|
|
283
300
|
};
|
|
284
301
|
async function createElementOnApi(client, integrationId, element) {
|
|
285
302
|
const elementType = folderToElementType[element.folder];
|
|
286
|
-
const name = element.data.name ||
|
|
303
|
+
const name = element.data.name ||
|
|
304
|
+
element.defaultName ||
|
|
305
|
+
sentenceCase(element.key);
|
|
287
306
|
const description = element.data.description;
|
|
288
307
|
const result = await client.request(CreateElementMutationDocument, {
|
|
289
308
|
integrationId,
|
|
@@ -301,28 +320,30 @@ async function createElementOnApi(client, integrationId, element) {
|
|
|
301
320
|
}
|
|
302
321
|
return { id, name };
|
|
303
322
|
}
|
|
323
|
+
function buildShadowData(element, name, description, data) {
|
|
324
|
+
if (isEndpointList(element)) {
|
|
325
|
+
return { ...data };
|
|
326
|
+
}
|
|
327
|
+
const finalName = element.data.name || name;
|
|
328
|
+
const finalDescription = element.data.description || description || undefined;
|
|
329
|
+
return {
|
|
330
|
+
...(finalName ? { name: finalName } : {}),
|
|
331
|
+
...(finalDescription ? { description: finalDescription } : {}),
|
|
332
|
+
...data,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
304
335
|
function writeShadowFileAndRecord(fsImpl, element, great, source, included) {
|
|
305
|
-
const name = element.data.name || included.name;
|
|
306
|
-
const description = element.data.description ||
|
|
307
|
-
included.description ||
|
|
308
|
-
undefined;
|
|
309
336
|
const content = included.content;
|
|
310
|
-
const fileData = {
|
|
311
|
-
[SHADOW_MARKER]: true,
|
|
312
|
-
...(name ? { name } : {}),
|
|
313
|
-
...(description ? { description } : {}),
|
|
314
|
-
...content?.data,
|
|
315
|
-
};
|
|
316
|
-
fsImpl.writeFileSync(element.filePath, JSON.stringify(fileData, null, 2));
|
|
317
337
|
setElementRecord(great, element.folder, element.key, {
|
|
318
338
|
id: included.id,
|
|
319
339
|
...(content?.createdAt ? { timestamp: content.createdAt } : {}),
|
|
320
|
-
|
|
340
|
+
hash: hashContent({ ...content?.data }),
|
|
321
341
|
source,
|
|
322
342
|
...(element.provenance && element.provenance.length > 0
|
|
323
343
|
? { provenance: element.provenance }
|
|
324
344
|
: {}),
|
|
325
345
|
});
|
|
346
|
+
writeElementFile(undefined, element.folder, element.key, buildShadowData(element, included.name, included.description, content?.data), great, fsImpl, element.filePath);
|
|
326
347
|
}
|
|
327
348
|
async function includeShadowElement(element, graphqlClient, integrationId, fsImpl, log, great) {
|
|
328
349
|
const source = element.source;
|
|
@@ -347,7 +368,7 @@ async function includeShadowElement(element, graphqlClient, integrationId, fsImp
|
|
|
347
368
|
const localDesc = element.data.description || '';
|
|
348
369
|
const nameDiffers = localName !== (included.name || '');
|
|
349
370
|
const descDiffers = localDesc !== (included.description || '');
|
|
350
|
-
if (nameDiffers || descDiffers) {
|
|
371
|
+
if (!isEndpointList(element) && (nameDiffers || descDiffers)) {
|
|
351
372
|
const updateResult = await graphqlClient.request(UpdateElementMutationDocument, {
|
|
352
373
|
id: included.id,
|
|
353
374
|
name: nameDiffers ? localName : undefined,
|
|
@@ -371,13 +392,11 @@ async function updateElementContent(client, elementId, content) {
|
|
|
371
392
|
return result.data?.setElementContent?.content?.createdAt;
|
|
372
393
|
}
|
|
373
394
|
function updateLocalFile(fsImpl, element, great, updatedId, updatedTimestamp, generatedName, keepValue = false) {
|
|
374
|
-
const
|
|
375
|
-
const parsed = parseJson(content);
|
|
376
|
-
const { name, description, value, ref, ...data } = parsed;
|
|
395
|
+
const { name, description, value, ref, ...data } = element.data;
|
|
377
396
|
const existing = getElementRecord(great, element.folder, element.key);
|
|
378
397
|
const id = updatedId ?? existing?.id;
|
|
379
398
|
const timestamp = updatedTimestamp ?? existing?.timestamp;
|
|
380
|
-
const finalName = generatedName || name;
|
|
399
|
+
const finalName = isEndpointList(element) ? undefined : generatedName || name;
|
|
381
400
|
const orderedData = {
|
|
382
401
|
...(finalName ? { name: finalName } : {}),
|
|
383
402
|
...(description ? { description } : {}),
|
|
@@ -385,12 +404,24 @@ function updateLocalFile(fsImpl, element, great, updatedId, updatedTimestamp, ge
|
|
|
385
404
|
...(keepValue && value !== undefined ? { value } : {}),
|
|
386
405
|
...(keepValue && ref !== undefined ? { ref } : {}),
|
|
387
406
|
};
|
|
388
|
-
fsImpl.writeFileSync(element.filePath, JSON.stringify(orderedData, null, 2));
|
|
389
407
|
setElementRecord(great, element.folder, element.key, {
|
|
390
408
|
...(id ? { id } : {}),
|
|
391
409
|
...(timestamp ? { timestamp } : {}),
|
|
392
410
|
hash: hashContent(orderedData),
|
|
393
411
|
});
|
|
412
|
+
writeElementFile(undefined, element.folder, element.key, orderedData, great, fsImpl, element.filePath);
|
|
413
|
+
}
|
|
414
|
+
async function restoreShadowFile(element, graphqlClient, fsImpl, great, log) {
|
|
415
|
+
const remote = element.id
|
|
416
|
+
? await fetchElementById(graphqlClient, element.id, log)
|
|
417
|
+
: undefined;
|
|
418
|
+
if (!remote) {
|
|
419
|
+
log(chalk.red(`Could not restore ${element.folder}/${element.key} from its source — the local changes are kept but not pushed`));
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const data = (remote.content?.data ?? {});
|
|
423
|
+
writeElementFile(undefined, element.folder, element.key, buildShadowData(element, undefined, undefined, data), great, fsImpl, element.filePath);
|
|
424
|
+
log(chalk.yellow(`Restored ${element.folder}/${element.key} from its source — the local changes were discarded`));
|
|
394
425
|
}
|
|
395
426
|
function recordElementProgress(great, element, fields) {
|
|
396
427
|
const existing = getElementRecord(great, element.folder, element.key);
|
|
@@ -402,10 +433,14 @@ function recordElementProgress(great, element, fields) {
|
|
|
402
433
|
function buildRemoteElementsMap(elements) {
|
|
403
434
|
const remoteElements = new Map();
|
|
404
435
|
for (const element of elements) {
|
|
436
|
+
const folder = typeToFolder[element.__typename];
|
|
437
|
+
if (!folder) {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
405
440
|
remoteElements.set(element.id, {
|
|
406
441
|
id: element.id,
|
|
407
442
|
key: element.key,
|
|
408
|
-
folder
|
|
443
|
+
folder,
|
|
409
444
|
checksum: element.content?.checksum,
|
|
410
445
|
contentCreatedAt: element.content?.createdAt,
|
|
411
446
|
name: element.name,
|
|
@@ -440,7 +475,7 @@ async function createOrUpdateElement(element, graphqlClient, integrationId, fsIm
|
|
|
440
475
|
}
|
|
441
476
|
else {
|
|
442
477
|
const apiElement = apiElementsMap.get(id);
|
|
443
|
-
if (apiElement) {
|
|
478
|
+
if (apiElement && !isEndpointList(element)) {
|
|
444
479
|
const localName = element.data.name || '';
|
|
445
480
|
const localDesc = element.data.description;
|
|
446
481
|
const apiName = apiElement.name || '';
|
|
@@ -459,7 +494,7 @@ async function createOrUpdateElement(element, graphqlClient, integrationId, fsIm
|
|
|
459
494
|
}
|
|
460
495
|
}
|
|
461
496
|
}
|
|
462
|
-
if (element.source) {
|
|
497
|
+
if (element.source && !element.detach) {
|
|
463
498
|
const remote = apiElementsMap.get(id);
|
|
464
499
|
const pinChanged = (element.source.timestamp ?? null) !== (remote?.sourceTimestamp ?? null);
|
|
465
500
|
const provenanceChanged = !sameProvenance(element.provenance, remote?.provenance);
|
|
@@ -513,12 +548,31 @@ async function deleteElement(element, graphqlClient, log) {
|
|
|
513
548
|
const result = await graphqlClient.request(DeleteElementMutationDocument, {
|
|
514
549
|
id: element.id,
|
|
515
550
|
});
|
|
516
|
-
if (result.error) {
|
|
551
|
+
if (result.error && !isNotFoundError(result.error)) {
|
|
517
552
|
log(chalk.red(`Failed to delete element ${element.id}`));
|
|
518
553
|
return false;
|
|
519
554
|
}
|
|
520
555
|
return true;
|
|
521
556
|
}
|
|
557
|
+
async function resolveDetaches(toDetach, promptForDetachFn, graphqlClient, fsImpl, great, log) {
|
|
558
|
+
const detached = [];
|
|
559
|
+
for (const element of toDetach) {
|
|
560
|
+
let shouldDetach;
|
|
561
|
+
try {
|
|
562
|
+
shouldDetach = await promptForDetachFn(element, log);
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
return undefined;
|
|
566
|
+
}
|
|
567
|
+
if (shouldDetach) {
|
|
568
|
+
detached.push({ ...element, detach: true });
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
await restoreShadowFile(element, graphqlClient, fsImpl, great, log);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return detached;
|
|
575
|
+
}
|
|
522
576
|
function buildRemoteImportsMap(templateImports) {
|
|
523
577
|
const map = new Map();
|
|
524
578
|
for (const templateImport of templateImports) {
|
|
@@ -597,12 +651,12 @@ function logSummary(createdCount, includedCount, updatedCount, deletedCount, reg
|
|
|
597
651
|
log(`\n${chalk.green('✓')} ${parts.join(', ')}`);
|
|
598
652
|
}
|
|
599
653
|
}
|
|
600
|
-
export const action = (log, apiToken, client, fsImpl = fs, config, promptForValueSettingFn = promptForValueSetting) => async function pushIntegration(options) {
|
|
654
|
+
export const action = (log, apiToken, client, fsImpl = fs, config, promptForValueSettingFn = promptForValueSetting, promptForDetachFn = promptForDetach) => async function pushIntegration(options) {
|
|
601
655
|
const great = readGreatFile(undefined, fsImpl);
|
|
602
656
|
let integrationId = great.id;
|
|
603
657
|
if (!integrationId) {
|
|
604
658
|
log(chalk.yellow('No integration ID found'));
|
|
605
|
-
log('Creating integration
|
|
659
|
+
log('Creating integration in Integreat...\n');
|
|
606
660
|
const graphqlClient = getClient(apiToken, client, config);
|
|
607
661
|
const result = await createIntegrationFromFile(graphqlClient, apiToken ?? '', options ?? {}, config, fsImpl);
|
|
608
662
|
if (!result.success || !result.integration) {
|
|
@@ -640,7 +694,7 @@ export const action = (log, apiToken, client, fsImpl = fs, config, promptForValu
|
|
|
640
694
|
};
|
|
641
695
|
writeGreatFile(great, undefined, fsImpl);
|
|
642
696
|
integrationId = integration.id;
|
|
643
|
-
log(chalk.green('✓ Updated integration.json with
|
|
697
|
+
log(chalk.green('✓ Updated integration.json with the details from Integreat\n'));
|
|
644
698
|
}
|
|
645
699
|
const graphqlClient = getClient(apiToken, client, config);
|
|
646
700
|
const result = await graphqlClient.request(IntegrationForPushQueryDocument, { id: integrationId });
|
|
@@ -668,14 +722,32 @@ export const action = (log, apiToken, client, fsImpl = fs, config, promptForValu
|
|
|
668
722
|
const record = getElementRecord(great, local.folder, local.key);
|
|
669
723
|
local.id = record?.id;
|
|
670
724
|
local.timestamp = record?.timestamp;
|
|
725
|
+
local.hash = record?.hash;
|
|
671
726
|
local.source = record?.source;
|
|
672
727
|
local.provenance = record?.provenance;
|
|
673
728
|
}
|
|
674
|
-
const
|
|
729
|
+
const serviceNames = new Map(localElements
|
|
730
|
+
.filter((el) => el.folder === 'services' && el.data.name)
|
|
731
|
+
.map((el) => [el.key, String(el.data.name)]));
|
|
732
|
+
for (const local of localElements) {
|
|
733
|
+
if (isEndpointList(local)) {
|
|
734
|
+
local.defaultName = serviceNames.get(local.key);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
for (const warning of validateEndpointReferences(localElements, great)) {
|
|
738
|
+
log(chalk.yellow(`Warning: ${warning}`));
|
|
739
|
+
}
|
|
740
|
+
const { toCreate, toInclude, toUpdate, toDetach, toDelete, conflicts } = categorizeElements(localElements, apiElementsMap);
|
|
675
741
|
if (conflicts.length > 0) {
|
|
676
742
|
handleConflicts(conflicts, log);
|
|
677
743
|
return;
|
|
678
744
|
}
|
|
745
|
+
const detached = await resolveDetaches(toDetach, promptForDetachFn, graphqlClient, fsImpl, great, log);
|
|
746
|
+
if (!detached) {
|
|
747
|
+
log(chalk.yellow('\nPush cancelled'));
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
toUpdate.push(...detached);
|
|
679
751
|
const remoteImportsMap = buildRemoteImportsMap(integration.templateImports ?? []);
|
|
680
752
|
const importsToRegister = findImportsToRegister(great, remoteImportsMap);
|
|
681
753
|
if (toCreate.length +
|
|
@@ -687,7 +759,7 @@ export const action = (log, apiToken, client, fsImpl = fs, config, promptForValu
|
|
|
687
759
|
log(chalk.green('No changes to push'));
|
|
688
760
|
return;
|
|
689
761
|
}
|
|
690
|
-
let shouldSetValue
|
|
762
|
+
let shouldSetValue;
|
|
691
763
|
try {
|
|
692
764
|
shouldSetValue = await promptForValueSettingFn([...toCreate, ...toUpdate], log);
|
|
693
765
|
}
|