@factorialco/fcode-cli 2.3.0 → 3.0.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 +334 -117
- package/dist/commands/clone.d.ts +0 -12
- package/dist/commands/clone.js +22 -135
- package/dist/commands/{settings → config}/get.d.ts +1 -1
- package/dist/commands/{settings → config}/get.js +7 -7
- package/dist/commands/{settings → config}/remove.d.ts +1 -1
- package/dist/commands/{settings → config}/remove.js +6 -6
- package/dist/commands/{settings → config}/set.d.ts +1 -1
- package/dist/commands/{settings → config}/set.js +8 -8
- package/dist/commands/dependencies/diff.d.ts +9 -0
- package/dist/commands/dependencies/diff.js +15 -0
- package/dist/commands/dependencies/pull.d.ts +9 -0
- package/dist/commands/dependencies/pull.js +44 -1
- package/dist/commands/dependencies/status.d.ts +11 -0
- package/dist/commands/dependencies/status.js +43 -0
- package/dist/commands/diff.d.ts +12 -0
- package/dist/commands/diff.js +48 -0
- package/dist/commands/http.d.ts +1 -1
- package/dist/commands/http.js +7 -7
- package/dist/commands/i18n/diff.d.ts +9 -0
- package/dist/commands/i18n/diff.js +15 -0
- package/dist/commands/i18n/status.d.ts +3 -0
- package/dist/commands/i18n/status.js +1 -0
- package/dist/commands/modules/diff.d.ts +9 -0
- package/dist/commands/modules/diff.js +15 -0
- package/dist/commands/modules/status.d.ts +3 -0
- package/dist/commands/modules/status.js +1 -0
- package/dist/commands/processes/diff.d.ts +9 -0
- package/dist/commands/processes/diff.js +15 -0
- package/dist/commands/processes/status.d.ts +3 -0
- package/dist/commands/processes/status.js +1 -0
- package/dist/commands/pull.js +3 -3
- package/dist/commands/push.js +2 -2
- package/dist/commands/{team → settings}/aliases/delete.d.ts +1 -1
- package/dist/commands/{team → settings}/aliases/delete.js +6 -6
- package/dist/commands/{team → settings}/aliases/list.d.ts +1 -1
- package/dist/commands/{team → settings}/aliases/list.js +8 -8
- package/dist/commands/{team → settings}/aliases/set.d.ts +1 -1
- package/dist/commands/{team → settings}/aliases/set.js +8 -8
- package/dist/commands/settings/diff.d.ts +8 -0
- package/dist/commands/settings/diff.js +39 -0
- package/dist/commands/{team/push.d.ts → settings/pull.d.ts} +3 -3
- package/dist/commands/settings/pull.js +41 -0
- package/dist/commands/settings/push.d.ts +13 -0
- package/dist/commands/settings/push.js +103 -0
- package/dist/commands/settings/status.d.ts +8 -0
- package/dist/commands/settings/status.js +46 -0
- package/dist/commands/{team → settings}/versions/create.d.ts +1 -2
- package/dist/commands/settings/versions/create.js +36 -0
- package/dist/commands/{team → settings}/versions/delete.d.ts +1 -1
- package/dist/commands/{team → settings}/versions/delete.js +10 -10
- package/dist/commands/{team → settings}/versions/list.d.ts +1 -1
- package/dist/commands/{team → settings}/versions/list.js +8 -8
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +10 -7
- package/dist/commands/team/clone.d.ts +14 -0
- package/dist/commands/team/clone.js +91 -0
- package/dist/commands/team/pull.d.ts +3 -4
- package/dist/commands/team/pull.js +25 -19
- package/dist/commands/team/status.d.ts +3 -4
- package/dist/commands/team/status.js +34 -27
- package/dist/commands/variables/diff.d.ts +9 -0
- package/dist/commands/variables/diff.js +15 -0
- package/dist/commands/variables/status.d.ts +3 -0
- package/dist/commands/variables/status.js +1 -0
- package/dist/config/dev-team.d.ts +48 -0
- package/dist/config/dev-team.js +62 -0
- package/dist/config/workspace.d.ts +2 -2
- package/dist/config/workspace.js +4 -2
- package/dist/core/commands/base-command.js +5 -0
- package/dist/core/commands/dependency-command.d.ts +2 -1
- package/dist/core/commands/dependency-command.js +3 -0
- package/dist/core/commands/i18n-command.js +2 -0
- package/dist/core/commands/modules-command.js +2 -0
- package/dist/core/commands/processes-command.js +2 -0
- package/dist/core/commands/resource-command.d.ts +26 -1
- package/dist/core/commands/resource-command.js +100 -3
- package/dist/core/commands/variables-command.d.ts +7 -0
- package/dist/core/commands/variables-command.js +13 -0
- package/dist/core/dependencies/env-dependencies-command.js +6 -3
- package/dist/core/executors/javascript-execution-task.js +36 -5
- package/dist/core/types.d.ts +59 -9
- package/dist/core/types.js +64 -10
- package/dist/core/utils/dependencies.js +4 -1
- package/dist/env.js +1 -1
- package/dist/repositories/process.d.ts +8 -2
- package/dist/repositories/process.js +29 -15
- package/dist/repositories/programming-language-manifest.d.ts +31 -1
- package/dist/repositories/programming-language-manifest.js +96 -2
- package/dist/repositories/settings.d.ts +52 -0
- package/dist/repositories/settings.js +214 -0
- package/dist/runtime/libs/python/fcode/context.py +42 -8
- package/dist/services/dashboard-client.d.ts +31 -0
- package/dist/services/dashboard-client.js +99 -0
- package/dist/services/dev-team-service.d.ts +41 -0
- package/dist/services/dev-team-service.js +162 -0
- package/dist/services/fcode-graphql-client.d.ts +17 -2
- package/dist/services/fcode-graphql-client.js +127 -15
- package/dist/services/locale-resolver.d.ts +17 -1
- package/dist/services/locale-resolver.js +62 -7
- package/dist/services/resource-differ.d.ts +60 -0
- package/dist/services/resource-differ.js +135 -0
- package/dist/services/skills-installer.d.ts +16 -0
- package/dist/services/skills-installer.js +77 -0
- package/dist/services/team-versioning.d.ts +16 -0
- package/dist/services/team-versioning.js +40 -0
- package/dist/services/webhook-auth.js +1 -1
- package/dist/services/workspace-cloner.d.ts +31 -0
- package/dist/services/workspace-cloner.js +95 -0
- package/dist/utils/dev-slug.d.ts +12 -0
- package/dist/utils/dev-slug.js +37 -0
- package/dist/utils/diff.d.ts +19 -0
- package/dist/utils/diff.js +58 -0
- package/dist/utils/gitignore.d.ts +3 -1
- package/dist/utils/gitignore.js +11 -2
- package/dist/utils/slugify.d.ts +17 -0
- package/dist/utils/slugify.js +41 -0
- package/oclif.manifest.json +433 -113
- package/package.json +12 -7
- package/dist/commands/team/push.js +0 -52
- package/dist/commands/team/versions/create.js +0 -42
- package/dist/repositories/team.d.ts +0 -31
- package/dist/repositories/team.js +0 -127
|
@@ -4,6 +4,7 @@ const script_library_1 = require("../../repositories/script-library");
|
|
|
4
4
|
const resource_merger_1 = require("../resource-merger");
|
|
5
5
|
const resource_pusher_1 = require("../resource-pusher");
|
|
6
6
|
const resource_command_1 = require("./resource-command");
|
|
7
|
+
const resource_differ_1 = require("../../services/resource-differ");
|
|
7
8
|
class ModulesCommand extends resource_command_1.default {
|
|
8
9
|
async init() {
|
|
9
10
|
await super.init();
|
|
@@ -11,6 +12,7 @@ class ModulesCommand extends resource_command_1.default {
|
|
|
11
12
|
this._resourceMerger = new resource_merger_1.default(this._resourceRepository);
|
|
12
13
|
this._resourcePusher = new resource_pusher_1.default(this._resourceRepository, this._fcodeGraphQLClient);
|
|
13
14
|
this._resourceQuery = () => this._fcodeGraphQLClient.allScriptLibraries.bind(this._fcodeGraphQLClient)();
|
|
15
|
+
this._diffFilesFor = resource_differ_1.moduleDiffFiles;
|
|
14
16
|
this._versionedResourceQuery = (id) => this._fcodeGraphQLClient.allVersionedScriptLibraries.bind(this._fcodeGraphQLClient)(id);
|
|
15
17
|
this._pushVersionedResourceMutation = (versionedScriptLibrary) => this._fcodeGraphQLClient.createVersionedScriptLibrary.bind(this._fcodeGraphQLClient)(versionedScriptLibrary);
|
|
16
18
|
}
|
|
@@ -5,6 +5,7 @@ const process_1 = require("../../repositories/process");
|
|
|
5
5
|
const resource_merger_1 = require("../resource-merger");
|
|
6
6
|
const resource_pusher_1 = require("../resource-pusher");
|
|
7
7
|
const resource_command_1 = require("./resource-command");
|
|
8
|
+
const resource_differ_1 = require("../../services/resource-differ");
|
|
8
9
|
class ProcessesCommand extends resource_command_1.default {
|
|
9
10
|
async init() {
|
|
10
11
|
await super.init();
|
|
@@ -12,6 +13,7 @@ class ProcessesCommand extends resource_command_1.default {
|
|
|
12
13
|
this._resourceMerger = new resource_merger_1.default(this._resourceRepository);
|
|
13
14
|
this._resourcePusher = new resource_pusher_1.default(this._resourceRepository, this._fcodeGraphQLClient);
|
|
14
15
|
this._resourceQuery = () => this._fcodeGraphQLClient.allProcesses.bind(this._fcodeGraphQLClient)();
|
|
16
|
+
this._diffFilesFor = resource_differ_1.processDiffFiles;
|
|
15
17
|
this._versionedResourceQuery = (id) => this._fcodeGraphQLClient.allVersionedProcesses.bind(this._fcodeGraphQLClient)(id);
|
|
16
18
|
this._pushVersionedResourceMutation = (versionedProcess) => this._fcodeGraphQLClient.createVersionedProcesses.bind(this._fcodeGraphQLClient)(versionedProcess);
|
|
17
19
|
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { ResourceStatus, type AddResourceOptions, type MergedResource, type Resource } from '../types';
|
|
2
2
|
import ResourceRepositoryBase from '../../repositories/resource';
|
|
3
3
|
import ResourceMerger from '../resource-merger';
|
|
4
4
|
import ResourcePusher from '../resource-pusher';
|
|
5
5
|
import ApiClientCommand from './api-client-command';
|
|
6
|
+
import { PseudoFile } from '../../utils/diff';
|
|
7
|
+
import { DiffSection, ResourcePair } from '../../services/resource-differ';
|
|
8
|
+
/** A status meaning the two sides agree, so there is nothing to pull, push or diff. */
|
|
9
|
+
export declare const isUnchangedStatus: (status: ResourceStatus) => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* An inherited resource the parent workspace owns and the cloud agrees on is noise in `status`:
|
|
12
|
+
* there is nothing to pull or push. It comes back as soon as it differs — or with --showInherited.
|
|
13
|
+
*/
|
|
14
|
+
export declare const isUnchangedInherited: (resource: MergedResource) => boolean;
|
|
6
15
|
export default abstract class ResourceCommand<R extends Resource> extends ApiClientCommand {
|
|
7
16
|
_resourceMerger: ResourceMerger<R>;
|
|
8
17
|
_resourcePusher: ResourcePusher<R>;
|
|
9
18
|
_resourceQuery: () => Promise<Array<R>>;
|
|
19
|
+
_diffFilesFor: (pair: ResourcePair<R>) => Array<PseudoFile>;
|
|
10
20
|
_resourceRepository: ResourceRepositoryBase<R>;
|
|
11
21
|
protected resourceSlug: string;
|
|
12
22
|
protected filterResource: (slug: string) => boolean;
|
|
@@ -20,5 +30,20 @@ export default abstract class ResourceCommand<R extends Resource> extends ApiCli
|
|
|
20
30
|
removeResource(slug: string): Promise<void>;
|
|
21
31
|
pushResources(): Promise<void>;
|
|
22
32
|
resourcesLog(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* One heading per resource, so a patch is always attributable to a slug and its status. Variables
|
|
35
|
+
* override this: they share a single .env file, and one patch over it reads better than one per key.
|
|
36
|
+
*
|
|
37
|
+
* `allPairs` carries every resource, including the unchanged ones, for a renderer that needs the
|
|
38
|
+
* whole set to place a change in context; `diffable` is only what a status says has changed.
|
|
39
|
+
*/
|
|
40
|
+
protected diffSections(diffable: Array<ResourcePair<R>>, allPairs: Array<ResourcePair<R>>): Array<DiffSection>;
|
|
41
|
+
/** Names the resource a patch belongs to, flagging an inherited one as the parent's to fix. */
|
|
42
|
+
protected diffLabel(pair: ResourcePair<R>): string;
|
|
43
|
+
/**
|
|
44
|
+
* Prints a unified diff of everything that differs between the workspace and the cloud, and
|
|
45
|
+
* reports whether anything did — which is what makes `fcode diff` exit non-zero.
|
|
46
|
+
*/
|
|
47
|
+
resourcesDiff(): Promise<boolean>;
|
|
23
48
|
resourcesTableLog(resources: Array<MergedResource>): Promise<void>;
|
|
24
49
|
}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isUnchangedInherited = exports.isUnchangedStatus = void 0;
|
|
3
4
|
const color_1 = require("@oclif/color");
|
|
4
5
|
const cli_1 = require("../../utils/cli");
|
|
6
|
+
const types_1 = require("../types");
|
|
5
7
|
const api_client_command_1 = require("./api-client-command");
|
|
6
8
|
const colorize_resource_1 = require("../../utils/colorize-resource");
|
|
9
|
+
const diff_1 = require("../../utils/diff");
|
|
10
|
+
const resource_differ_1 = require("../../services/resource-differ");
|
|
11
|
+
// A sensitive variable never compares equal — its content hash is empty — so SENSITIVE is the
|
|
12
|
+
// resting state of an inherited secret, not a change, and counts as unchanged here.
|
|
13
|
+
const UNCHANGED_STATUSES = new Set([types_1.ResourceStatus.UP_TO_DATE, types_1.ResourceStatus.SENSITIVE]);
|
|
14
|
+
/** A status meaning the two sides agree, so there is nothing to pull, push or diff. */
|
|
15
|
+
const isUnchangedStatus = (status) => UNCHANGED_STATUSES.has(status);
|
|
16
|
+
exports.isUnchangedStatus = isUnchangedStatus;
|
|
17
|
+
/**
|
|
18
|
+
* An inherited resource the parent workspace owns and the cloud agrees on is noise in `status`:
|
|
19
|
+
* there is nothing to pull or push. It comes back as soon as it differs — or with --showInherited.
|
|
20
|
+
*/
|
|
21
|
+
const isUnchangedInherited = (resource) => Boolean(resource.resolvingTeamSlug) && (0, exports.isUnchangedStatus)(resource.status);
|
|
22
|
+
exports.isUnchangedInherited = isUnchangedInherited;
|
|
7
23
|
class ResourceCommand extends api_client_command_1.default {
|
|
8
24
|
constructor() {
|
|
9
25
|
super(...arguments);
|
|
@@ -60,18 +76,99 @@ class ResourceCommand extends api_client_command_1.default {
|
|
|
60
76
|
async resourcesLog() {
|
|
61
77
|
cli_1.default.log(color_1.default.cyan(`\n${this._resourceRepository._repositoryName} status`));
|
|
62
78
|
const mergedResources = await this._resourceMerger.mergeStatus(await this.getRemoteResources(), await this.getLocalResources());
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
const { flags: { showInherited }, } = await this.parse(this.ctor);
|
|
80
|
+
const visibleResources = showInherited ? mergedResources : mergedResources.filter((resource) => !(0, exports.isUnchangedInherited)(resource));
|
|
81
|
+
const hiddenCount = mergedResources.length - visibleResources.length;
|
|
82
|
+
if (visibleResources.length > 0) {
|
|
83
|
+
await this.resourcesTableLog(visibleResources);
|
|
65
84
|
}
|
|
66
|
-
else {
|
|
85
|
+
else if (mergedResources.length === 0) {
|
|
67
86
|
cli_1.default.log(`No ${this._resourceRepository._repositoryName} found`);
|
|
68
87
|
}
|
|
88
|
+
if (hiddenCount > 0) {
|
|
89
|
+
cli_1.default.log(color_1.default.cyan(`ℹ️ ${hiddenCount} inherited ${this._resourceRepository._repositoryName} up to date (hidden). Use --showInherited to list them.`));
|
|
90
|
+
}
|
|
69
91
|
const slugsNotAdded = await this.findSlugsNotAdded();
|
|
70
92
|
if (slugsNotAdded.length > 0) {
|
|
71
93
|
const warningText = `\nℹ️ ${slugsNotAdded.length} ${this._resourceRepository._repositoryName} only existing in local: ${slugsNotAdded.join(', ')}\n Use command 'fcode ${this._resourceRepository._repositoryName}:add' to keep track of these resources`;
|
|
72
94
|
cli_1.default.log(color_1.default.yellow(warningText));
|
|
73
95
|
}
|
|
74
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* One heading per resource, so a patch is always attributable to a slug and its status. Variables
|
|
99
|
+
* override this: they share a single .env file, and one patch over it reads better than one per key.
|
|
100
|
+
*
|
|
101
|
+
* `allPairs` carries every resource, including the unchanged ones, for a renderer that needs the
|
|
102
|
+
* whole set to place a change in context; `diffable` is only what a status says has changed.
|
|
103
|
+
*/
|
|
104
|
+
diffSections(diffable, allPairs) {
|
|
105
|
+
return diffable.map((pair) => ({
|
|
106
|
+
label: this.diffLabel(pair),
|
|
107
|
+
files: this._diffFilesFor(pair),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
/** Names the resource a patch belongs to, flagging an inherited one as the parent's to fix. */
|
|
111
|
+
diffLabel(pair) {
|
|
112
|
+
const label = `${pair.status} ${this._resourceRepository._repositoryName}/${pair.slug}`;
|
|
113
|
+
const inheritedTeam = (0, resource_differ_1.inheritedFrom)(pair);
|
|
114
|
+
return inheritedTeam ? `${label} 🔗 inherited from '${inheritedTeam}' (read-only — run pull to update)` : label;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Prints a unified diff of everything that differs between the workspace and the cloud, and
|
|
118
|
+
* reports whether anything did — which is what makes `fcode diff` exit non-zero.
|
|
119
|
+
*/
|
|
120
|
+
async resourcesDiff() {
|
|
121
|
+
cli_1.default.log(color_1.default.cyan(`\n${this._resourceRepository._repositoryName} diff`));
|
|
122
|
+
const pairs = await (0, resource_differ_1.pairResources)(await this.getRemoteResources(), await this.getLocalResources(), (slug) => this._resourceRepository.existsMetadata(slug));
|
|
123
|
+
const notes = [];
|
|
124
|
+
const diffable = [];
|
|
125
|
+
let hiddenInherited = 0;
|
|
126
|
+
let sensitivityChanged = false;
|
|
127
|
+
for (const pair of pairs) {
|
|
128
|
+
// Same rule `status` applies: an inherited resource the cloud agrees on has nothing to show,
|
|
129
|
+
// but one that drifted is exactly what the user needs — a parent moving it is never swallowed.
|
|
130
|
+
if ((0, resource_differ_1.inheritedFrom)(pair) && (0, exports.isUnchangedStatus)(pair.status)) {
|
|
131
|
+
hiddenInherited++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// A sensitive value is unknowable on both sides, so there is nothing to diff; a sensitivity
|
|
135
|
+
// change is a real difference the patch cannot show, so it is reported instead.
|
|
136
|
+
if (pair.status === types_1.ResourceStatus.SENSITIVITY_CHANGED) {
|
|
137
|
+
sensitivityChanged = true;
|
|
138
|
+
notes.push(color_1.default.yellow(`${pair.status} ${pair.slug} — sensitivity differs between local and cloud (values are never shown)`));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
// An up-to-date resource is skipped rather than rendered and found equal: its two sides can
|
|
142
|
+
// still serialize differently (key order in parametersSchema.json, say) where the content
|
|
143
|
+
// hash — which is what "up to date" means — says they are the same.
|
|
144
|
+
if ((0, exports.isUnchangedStatus)(pair.status)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
diffable.push(pair);
|
|
148
|
+
}
|
|
149
|
+
const sections = this.diffSections(diffable, pairs)
|
|
150
|
+
.map((section) => ({ ...section, files: section.files.filter((file) => (0, diff_1.hasDifference)(file)) }))
|
|
151
|
+
.filter((section) => section.files.length > 0);
|
|
152
|
+
for (const section of sections) {
|
|
153
|
+
cli_1.default.log('');
|
|
154
|
+
cli_1.default.log((0, colorize_resource_1.colorizeByStatus)(section.label, section.label));
|
|
155
|
+
for (const file of section.files) {
|
|
156
|
+
cli_1.default.log((0, diff_1.colorizeDiff)((0, diff_1.renderUnifiedDiff)(file)));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const note of notes) {
|
|
160
|
+
cli_1.default.log(note);
|
|
161
|
+
}
|
|
162
|
+
if (sections.length === 0 && !sensitivityChanged) {
|
|
163
|
+
cli_1.default.log(color_1.default.green(`✅ ${this._resourceRepository._repositoryName} up to date`));
|
|
164
|
+
}
|
|
165
|
+
// Counted rather than listed: a workspace built on a parent inherits dozens of resources, and a
|
|
166
|
+
// line each would bury the diff it was run for. Only the ones with nothing to show are in here.
|
|
167
|
+
if (hiddenInherited > 0) {
|
|
168
|
+
cli_1.default.log(color_1.default.cyan(`ℹ️ ${hiddenInherited} inherited ${this._resourceRepository._repositoryName} up to date (nothing to diff).`));
|
|
169
|
+
}
|
|
170
|
+
return sections.length > 0 || sensitivityChanged;
|
|
171
|
+
}
|
|
75
172
|
async resourcesTableLog(resources) {
|
|
76
173
|
cli_1.default.table(resources, {
|
|
77
174
|
name: {
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Variable } from '../types';
|
|
2
2
|
import ResourceCommand from './resource-command';
|
|
3
|
+
import { DiffSection, ResourcePair } from '../../services/resource-differ';
|
|
3
4
|
export default abstract class VariablesCommand extends ResourceCommand<Variable> {
|
|
4
5
|
init(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Variables share their files, so they diff as one patch per file rather than one per key.
|
|
8
|
+
* Rendered from every variable, not just the changed ones, so hunks carry the surrounding keys
|
|
9
|
+
* and the line numbers of the real file.
|
|
10
|
+
*/
|
|
11
|
+
protected diffSections(diffable: Array<ResourcePair<Variable>>, allPairs: Array<ResourcePair<Variable>>): Array<DiffSection>;
|
|
5
12
|
}
|
|
@@ -4,6 +4,7 @@ const variable_1 = require("../../repositories/variable");
|
|
|
4
4
|
const resource_merger_1 = require("../resource-merger");
|
|
5
5
|
const resource_pusher_1 = require("../resource-pusher");
|
|
6
6
|
const resource_command_1 = require("./resource-command");
|
|
7
|
+
const resource_differ_1 = require("../../services/resource-differ");
|
|
7
8
|
class VariablesCommand extends resource_command_1.default {
|
|
8
9
|
async init() {
|
|
9
10
|
await super.init();
|
|
@@ -11,6 +12,18 @@ class VariablesCommand extends resource_command_1.default {
|
|
|
11
12
|
this._resourceMerger = new resource_merger_1.default(this._resourceRepository);
|
|
12
13
|
this._resourcePusher = new resource_pusher_1.default(this._resourceRepository, this._fcodeGraphQLClient);
|
|
13
14
|
this._resourceQuery = () => this._fcodeGraphQLClient.allVariables.bind(this._fcodeGraphQLClient)();
|
|
15
|
+
this._diffFilesFor = (pair) => (0, resource_differ_1.variablesEnvDiffFiles)([pair]);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Variables share their files, so they diff as one patch per file rather than one per key.
|
|
19
|
+
* Rendered from every variable, not just the changed ones, so hunks carry the surrounding keys
|
|
20
|
+
* and the line numbers of the real file.
|
|
21
|
+
*/
|
|
22
|
+
diffSections(diffable, allPairs) {
|
|
23
|
+
if (diffable.length === 0) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
return [{ label: resource_differ_1.VARIABLES_DIFF_PATH, files: (0, resource_differ_1.variablesEnvDiffFiles)(allPairs) }];
|
|
14
27
|
}
|
|
15
28
|
}
|
|
16
29
|
exports.default = VariablesCommand;
|
|
@@ -25,7 +25,10 @@ class EnvDependenciesCommand extends api_client_command_1.default {
|
|
|
25
25
|
fs.rmSync(this.envPath, { recursive: true });
|
|
26
26
|
}
|
|
27
27
|
const manifest = await this.getManifest();
|
|
28
|
-
|
|
28
|
+
// The effective set — own dependencies over inherited ones — because that is what the platform
|
|
29
|
+
// installs, and the directory is named after the hash of what is installed.
|
|
30
|
+
const dependencies = manifest.effectiveDependencies;
|
|
31
|
+
const installationPath = this.installationPath(dependencies);
|
|
29
32
|
if (fs.existsSync(installationPath)) {
|
|
30
33
|
if (force) {
|
|
31
34
|
fs.rmSync(installationPath, { recursive: true });
|
|
@@ -38,12 +41,12 @@ class EnvDependenciesCommand extends api_client_command_1.default {
|
|
|
38
41
|
await this.createEnv();
|
|
39
42
|
cli_1.default.log(`Installing Factorial Code ${(0, types_1.programmingLanguageDisplayName)(this.programmingLanguage)} dependencies... (This process might take some time ⌛️)`);
|
|
40
43
|
cli_1.default.log('====================================');
|
|
41
|
-
await this.installDependencies(installationPath,
|
|
44
|
+
await this.installDependencies(installationPath, dependencies);
|
|
42
45
|
cli_1.default.log('====================================');
|
|
43
46
|
cli_1.default.log(color_1.default.green(`Factorial Code ${(0, types_1.programmingLanguageDisplayName)(this.programmingLanguage)} dependencies successfully installed in ${installationPath} 🤩\n\n`));
|
|
44
47
|
}
|
|
45
48
|
async check() {
|
|
46
|
-
const installationPath = this.installationPath((await this.getManifest()).
|
|
49
|
+
const installationPath = this.installationPath((await this.getManifest()).effectiveDependencies);
|
|
47
50
|
if (!fs.existsSync(installationPath)) {
|
|
48
51
|
cli_1.default.log(color_1.default.yellow(`⚠️ ${(0, types_1.programmingLanguageDisplayName)(this.programmingLanguage)} dependencies need to be installed.`));
|
|
49
52
|
}
|
|
@@ -593,13 +593,44 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
593
593
|
}
|
|
594
594
|
};
|
|
595
595
|
})(),
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
//
|
|
596
|
+
// A workspace directory holds no published snapshots, so a pinned call resolves against
|
|
597
|
+
// the files on disk — the same per-file fallback the cloud applies to a locale that was
|
|
598
|
+
// never published at that tag. A locale option resolves against that locale's own files,
|
|
599
|
+
// falling back key by key to the merged translations, exactly like the cloud executors,
|
|
600
|
+
// shortening a locale nothing matches the same way they do.
|
|
599
601
|
// Own properties only and no array arguments, exactly like the cloud executors.
|
|
600
|
-
i18n: Object.assign((key, args,
|
|
602
|
+
i18n: Object.assign((key, args, options) => {
|
|
601
603
|
const translations = ${JSON.stringify(metadata.i18n.translations, null, 2)};
|
|
602
|
-
const
|
|
604
|
+
const byLocale = ${JSON.stringify(metadata.i18n.byLocale, null, 2)};
|
|
605
|
+
const requested = options && typeof options === 'object' && options.locale !== undefined && options.locale !== null
|
|
606
|
+
? String(options.locale)
|
|
607
|
+
: undefined;
|
|
608
|
+
// An identifier no locale matches is shortened one segment at a time ('en-gb' reads
|
|
609
|
+
// 'en'), by name first and ignoring case only as a last resort — the same chain the
|
|
610
|
+
// cloud resolves, so a local run answers a regional variant the same way.
|
|
611
|
+
const localeMaps = [];
|
|
612
|
+
for (let candidate = requested; candidate; ) {
|
|
613
|
+
const names = Object.keys(byLocale);
|
|
614
|
+
const lowered = candidate.toLowerCase();
|
|
615
|
+
const match = names.includes(candidate)
|
|
616
|
+
? candidate
|
|
617
|
+
: names.filter((name) => name.toLowerCase() === lowered).sort()[0];
|
|
618
|
+
if (match !== undefined && !localeMaps.includes(byLocale[match])) {
|
|
619
|
+
localeMaps.push(byLocale[match]);
|
|
620
|
+
}
|
|
621
|
+
const lastSeparator = Math.max(candidate.lastIndexOf('-'), candidate.lastIndexOf('_'));
|
|
622
|
+
candidate = lastSeparator > 0 ? candidate.slice(0, lastSeparator) : undefined;
|
|
623
|
+
}
|
|
624
|
+
let template;
|
|
625
|
+
for (const localeMap of localeMaps) {
|
|
626
|
+
template = Object.hasOwn(localeMap, key) ? localeMap[key] : undefined;
|
|
627
|
+
if (template !== undefined) {
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (template === undefined) {
|
|
632
|
+
template = Object.hasOwn(translations, key) ? translations[key] : undefined;
|
|
633
|
+
}
|
|
603
634
|
if (template === undefined) {
|
|
604
635
|
return key;
|
|
605
636
|
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export type MergedResource = MergedResourceRecord & {
|
|
|
101
101
|
status: ResourceStatus;
|
|
102
102
|
};
|
|
103
103
|
export type ProgrammingLanguage = 'JAVASCRIPT' | 'PYTHON';
|
|
104
|
+
export declare const PROGRAMMING_LANGUAGES: ReadonlyArray<ProgrammingLanguage>;
|
|
104
105
|
export declare const programmingLanguageDisplayName: (programmingLanguage: ProgrammingLanguage) => string;
|
|
105
106
|
export type WebhookAuthMode = 'NONE' | 'TEAM' | 'CUSTOM';
|
|
106
107
|
export declare const DEFAULT_WEBHOOK_AUTH_HEADER = "Authorization";
|
|
@@ -130,12 +131,30 @@ export interface ProcessForm {
|
|
|
130
131
|
appRole?: AppRole;
|
|
131
132
|
authMode?: FormAuthMode;
|
|
132
133
|
}
|
|
134
|
+
export interface ProcessUiTrigger {
|
|
135
|
+
enabled: boolean;
|
|
136
|
+
/** Identifier of the UI location the trigger is rendered in. */
|
|
137
|
+
locationId?: string;
|
|
138
|
+
/**
|
|
139
|
+
* Label shown on the trigger. May contain fcode.i18n("key") tokens, which the platform
|
|
140
|
+
* resolves when a process listing names a locale.
|
|
141
|
+
*/
|
|
142
|
+
label?: string;
|
|
143
|
+
/** f0 icon name, e.g. "Globe". */
|
|
144
|
+
icon?: string;
|
|
145
|
+
/**
|
|
146
|
+
* When true the trigger executes the process synchronously and returns the result
|
|
147
|
+
* envelope; otherwise the execution is fire-and-forget.
|
|
148
|
+
*/
|
|
149
|
+
awaitResult?: boolean;
|
|
150
|
+
}
|
|
133
151
|
export interface ProcessMetadataFields {
|
|
134
152
|
name: string;
|
|
135
153
|
description?: string;
|
|
136
154
|
tags: string[];
|
|
137
155
|
webhook?: ProcessWebhook;
|
|
138
156
|
form?: ProcessForm;
|
|
157
|
+
uiTrigger?: ProcessUiTrigger;
|
|
139
158
|
}
|
|
140
159
|
export declare class Process extends Resource {
|
|
141
160
|
id: string;
|
|
@@ -146,6 +165,7 @@ export declare class Process extends Resource {
|
|
|
146
165
|
tags: string[];
|
|
147
166
|
webhook?: ProcessWebhook;
|
|
148
167
|
form?: ProcessForm;
|
|
168
|
+
uiTrigger?: ProcessUiTrigger;
|
|
149
169
|
script: {
|
|
150
170
|
parametersSchema: any;
|
|
151
171
|
programmingLanguage: ProgrammingLanguage;
|
|
@@ -220,6 +240,20 @@ export declare class VersionedScriptLibrary extends Resource {
|
|
|
220
240
|
constructor(id: string, tag: string, sourceCode: string, programmingLanguage: ProgrammingLanguage);
|
|
221
241
|
get contentHash(): string;
|
|
222
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* A published snapshot of the dependencies a workspace declares for one language. Pulled read-only
|
|
245
|
+
* for visibility and git history: unlike process and module versions, these are never pushed back —
|
|
246
|
+
* `fcode settings:versions:create` is what publishes them.
|
|
247
|
+
*/
|
|
248
|
+
export declare class VersionedProgrammingLanguageManifest extends Resource {
|
|
249
|
+
id: string;
|
|
250
|
+
slug: string;
|
|
251
|
+
tag: string;
|
|
252
|
+
programmingLanguage: ProgrammingLanguage;
|
|
253
|
+
dependencies: Array<Dependency>;
|
|
254
|
+
constructor(tag: string, programmingLanguage: ProgrammingLanguage, dependencies: Array<Dependency>);
|
|
255
|
+
get contentHash(): string;
|
|
256
|
+
}
|
|
223
257
|
export declare class Variable extends Resource {
|
|
224
258
|
static ENV_KEY_MAX_LENGTH: number;
|
|
225
259
|
static ENV_KEY_REGEX: RegExp;
|
|
@@ -238,7 +272,14 @@ export declare class ProgrammingLanguageManifest extends Resource {
|
|
|
238
272
|
slug: string;
|
|
239
273
|
programmingLanguage: ProgrammingLanguage;
|
|
240
274
|
dependencies: Array<Dependency>;
|
|
241
|
-
|
|
275
|
+
inheritedDependencies: Array<Dependency>;
|
|
276
|
+
constructor(id: string, slug: string, programmingLanguage: ProgrammingLanguage, dependencies: Array<Dependency>, inheritedDependencies?: Array<Dependency>);
|
|
277
|
+
/**
|
|
278
|
+
* What an execution installs: this workspace's dependencies layered over the inherited ones, one
|
|
279
|
+
* entry per package name. Mirrors the platform's merge so a local run resolves the same install
|
|
280
|
+
* directory the cloud does.
|
|
281
|
+
*/
|
|
282
|
+
get effectiveDependencies(): Array<Dependency>;
|
|
242
283
|
get contentHash(): string;
|
|
243
284
|
}
|
|
244
285
|
export interface ErrorHandlerConfig {
|
|
@@ -246,8 +287,8 @@ export interface ErrorHandlerConfig {
|
|
|
246
287
|
tag?: string | null;
|
|
247
288
|
}
|
|
248
289
|
export interface TeamVersionManifestEntry {
|
|
249
|
-
resourceType: 'MODULE' | 'PROCESS';
|
|
250
|
-
resourceId
|
|
290
|
+
resourceType: 'DEPENDENCIES' | 'LOCALE' | 'MODULE' | 'PROCESS';
|
|
291
|
+
resourceId?: string | null;
|
|
251
292
|
slug: string;
|
|
252
293
|
outcome: 'CREATED' | 'FAILED' | 'SKIPPED_EXISTS' | 'SKIPPED_NO_TAG' | 'UPDATED';
|
|
253
294
|
error?: string | null;
|
|
@@ -273,23 +314,28 @@ export interface TeamVersionAlias {
|
|
|
273
314
|
export interface TeamVersionFileEntry {
|
|
274
315
|
tag: string;
|
|
275
316
|
comment?: string;
|
|
276
|
-
createdAt
|
|
317
|
+
createdAt?: string;
|
|
277
318
|
}
|
|
278
319
|
export interface TeamAliasFileEntry {
|
|
279
320
|
name: string;
|
|
280
321
|
tag: string;
|
|
281
322
|
}
|
|
282
|
-
export
|
|
323
|
+
export interface ParentTeamRef {
|
|
324
|
+
slug: string;
|
|
325
|
+
version?: string;
|
|
326
|
+
}
|
|
327
|
+
/** The workspace's settings.json: what `fcode settings:pull|push` syncs against the cloud team. */
|
|
328
|
+
export declare class WorkspaceSettings extends Resource {
|
|
283
329
|
id: string | undefined;
|
|
284
330
|
slug: string;
|
|
285
331
|
zoneId?: string;
|
|
286
332
|
errorHandlerConfig?: ErrorHandlerConfig;
|
|
287
|
-
|
|
333
|
+
parentTeams: ParentTeamRef[];
|
|
288
334
|
webhookAuth?: WebhookAuth;
|
|
289
335
|
primaryLocale?: string;
|
|
290
336
|
versions?: TeamVersionFileEntry[];
|
|
291
337
|
aliases?: TeamAliasFileEntry[];
|
|
292
|
-
constructor(slug: string,
|
|
338
|
+
constructor(slug: string, parentTeams: ParentTeamRef[], zoneId?: string, errorHandlerConfig?: ErrorHandlerConfig, webhookAuth?: WebhookAuth, primaryLocale?: string);
|
|
293
339
|
get contentHash(): string;
|
|
294
340
|
}
|
|
295
341
|
export interface RawErrorHandlerConfig {
|
|
@@ -300,13 +346,13 @@ export interface RawTeamSettings {
|
|
|
300
346
|
slug: string;
|
|
301
347
|
zoneId?: string;
|
|
302
348
|
errorHandlerConfig?: RawErrorHandlerConfig | null;
|
|
303
|
-
|
|
349
|
+
parentTeams: ParentTeamRef[];
|
|
304
350
|
webhookAuth?: WebhookAuth | null;
|
|
305
351
|
primaryLocale?: string | null;
|
|
306
352
|
}
|
|
307
353
|
export interface TeamUpdateInput {
|
|
308
354
|
zoneId?: string;
|
|
309
|
-
|
|
355
|
+
parentTeams?: ParentTeamRef[];
|
|
310
356
|
executionErrorHandlerConfig?: RawErrorHandlerConfig | null;
|
|
311
357
|
webhookAuth?: {
|
|
312
358
|
headerName?: string | null;
|
|
@@ -352,6 +398,9 @@ export declare const ForceFlag: {
|
|
|
352
398
|
export declare const ResourceSlugArg: {
|
|
353
399
|
resourceSlug: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
354
400
|
};
|
|
401
|
+
export declare const ShowInheritedFlag: {
|
|
402
|
+
showInherited: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
403
|
+
};
|
|
355
404
|
export declare const TeamNameArg: {
|
|
356
405
|
team: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
357
406
|
};
|
|
@@ -363,6 +412,7 @@ export declare const DependenciesFlags: {
|
|
|
363
412
|
export declare class Dependency {
|
|
364
413
|
name: string;
|
|
365
414
|
specifier: string;
|
|
415
|
+
resolvingTeamSlug?: string;
|
|
366
416
|
}
|
|
367
417
|
export declare class ServiceAccount extends Resource {
|
|
368
418
|
id: string;
|
package/dist/core/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ServiceAccount = exports.Dependency = exports.DependenciesFlags = exports.TeamNameArg = exports.ResourceSlugArg = exports.ForceFlag = exports.ScriptLibraryNotFound = exports.ProcessNotFound = exports.
|
|
3
|
+
exports.ServiceAccount = exports.Dependency = exports.DependenciesFlags = exports.TeamNameArg = exports.ShowInheritedFlag = exports.ResourceSlugArg = exports.ForceFlag = exports.ScriptLibraryNotFound = exports.ProcessNotFound = exports.WorkspaceSettings = exports.ProgrammingLanguageManifest = exports.Variable = exports.VersionedProgrammingLanguageManifest = exports.VersionedScriptLibrary = exports.Locale = exports.ScriptLibrary = exports.VersionedProcess = exports.Process = exports.DEFAULT_WEBHOOK_AUTH_HEADER = exports.programmingLanguageDisplayName = exports.PROGRAMMING_LANGUAGES = exports.ResourceStatus = exports.OnConflictResolution = exports.Resource = void 0;
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const crypto = require("node:crypto");
|
|
6
6
|
const canonical_hash_1 = require("../utils/canonical-hash");
|
|
@@ -28,6 +28,7 @@ var ResourceStatus;
|
|
|
28
28
|
ResourceStatus["SENSITIVE"] = "\uD83D\uDD12 (sensitive)";
|
|
29
29
|
ResourceStatus["SENSITIVITY_CHANGED"] = "\uD83D\uDEAB (sensitivity-changed)";
|
|
30
30
|
})(ResourceStatus || (exports.ResourceStatus = ResourceStatus = {}));
|
|
31
|
+
exports.PROGRAMMING_LANGUAGES = ['JAVASCRIPT', 'PYTHON'];
|
|
31
32
|
const programmingLanguageDisplayName = (programmingLanguage) => {
|
|
32
33
|
switch (programmingLanguage) {
|
|
33
34
|
case 'JAVASCRIPT':
|
|
@@ -49,6 +50,7 @@ class Process extends Resource {
|
|
|
49
50
|
this.tags = metadata.tags;
|
|
50
51
|
this.webhook = metadata.webhook;
|
|
51
52
|
this.form = metadata.form;
|
|
53
|
+
this.uiTrigger = metadata.uiTrigger;
|
|
52
54
|
this.script = script;
|
|
53
55
|
this.readme = readme;
|
|
54
56
|
this.manifest = settings.dependencies.scopedToProcess && manifest !== null ? manifest : { dependencies: [] };
|
|
@@ -65,6 +67,9 @@ class Process extends Resource {
|
|
|
65
67
|
tags: this.tags || [],
|
|
66
68
|
webhook: this.webhook || null,
|
|
67
69
|
form: this.form || null,
|
|
70
|
+
// Inserted only when set, so every process that predates UI triggers keeps the
|
|
71
|
+
// content hash already stored in .fcode (mirrors WorkspaceSettings.contentHash).
|
|
72
|
+
...(this.uiTrigger && { uiTrigger: this.uiTrigger }),
|
|
68
73
|
manifestDependencies: this.manifest.dependencies,
|
|
69
74
|
dependenciesScopedToProcess: this.settings.dependencies.scopedToProcess,
|
|
70
75
|
});
|
|
@@ -152,6 +157,25 @@ class VersionedScriptLibrary extends Resource {
|
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
159
|
exports.VersionedScriptLibrary = VersionedScriptLibrary;
|
|
160
|
+
/**
|
|
161
|
+
* A published snapshot of the dependencies a workspace declares for one language. Pulled read-only
|
|
162
|
+
* for visibility and git history: unlike process and module versions, these are never pushed back —
|
|
163
|
+
* `fcode settings:versions:create` is what publishes them.
|
|
164
|
+
*/
|
|
165
|
+
class VersionedProgrammingLanguageManifest extends Resource {
|
|
166
|
+
constructor(tag, programmingLanguage, dependencies) {
|
|
167
|
+
super();
|
|
168
|
+
this.id = `${tag}#${programmingLanguage}`;
|
|
169
|
+
this.slug = programmingLanguage;
|
|
170
|
+
this.tag = tag;
|
|
171
|
+
this.programmingLanguage = programmingLanguage;
|
|
172
|
+
this.dependencies = dependencies;
|
|
173
|
+
}
|
|
174
|
+
get contentHash() {
|
|
175
|
+
return crypto.createHash('md5').update(JSON.stringify(this.dependencies)).digest('hex');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
exports.VersionedProgrammingLanguageManifest = VersionedProgrammingLanguageManifest;
|
|
155
179
|
class Variable extends Resource {
|
|
156
180
|
constructor(id, key, value, isSensitive, resolvingTeamSlug) {
|
|
157
181
|
super();
|
|
@@ -185,12 +209,22 @@ exports.Variable = Variable;
|
|
|
185
209
|
Variable.ENV_KEY_MAX_LENGTH = 64;
|
|
186
210
|
Variable.ENV_KEY_REGEX = /^[A-Z_a-z]\w*$/;
|
|
187
211
|
class ProgrammingLanguageManifest extends Resource {
|
|
188
|
-
constructor(id, slug, programmingLanguage, dependencies) {
|
|
212
|
+
constructor(id, slug, programmingLanguage, dependencies, inheritedDependencies = []) {
|
|
189
213
|
super();
|
|
190
214
|
this.id = id;
|
|
191
215
|
this.slug = slug;
|
|
192
216
|
this.programmingLanguage = programmingLanguage;
|
|
193
217
|
this.dependencies = dependencies;
|
|
218
|
+
this.inheritedDependencies = inheritedDependencies;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* What an execution installs: this workspace's dependencies layered over the inherited ones, one
|
|
222
|
+
* entry per package name. Mirrors the platform's merge so a local run resolves the same install
|
|
223
|
+
* directory the cloud does.
|
|
224
|
+
*/
|
|
225
|
+
get effectiveDependencies() {
|
|
226
|
+
const ownNames = new Set(this.dependencies.map((dependency) => dependency.name));
|
|
227
|
+
return [...this.dependencies, ...this.inheritedDependencies.filter((dependency) => !ownNames.has(dependency.name))];
|
|
194
228
|
}
|
|
195
229
|
get contentHash() {
|
|
196
230
|
return crypto
|
|
@@ -200,11 +234,12 @@ class ProgrammingLanguageManifest extends Resource {
|
|
|
200
234
|
}
|
|
201
235
|
}
|
|
202
236
|
exports.ProgrammingLanguageManifest = ProgrammingLanguageManifest;
|
|
203
|
-
|
|
204
|
-
|
|
237
|
+
/** The workspace's settings.json: what `fcode settings:pull|push` syncs against the cloud team. */
|
|
238
|
+
class WorkspaceSettings extends Resource {
|
|
239
|
+
constructor(slug, parentTeams, zoneId, errorHandlerConfig, webhookAuth, primaryLocale) {
|
|
205
240
|
super();
|
|
206
241
|
this.slug = slug;
|
|
207
|
-
this.
|
|
242
|
+
this.parentTeams = parentTeams;
|
|
208
243
|
this.zoneId = zoneId;
|
|
209
244
|
this.errorHandlerConfig = errorHandlerConfig;
|
|
210
245
|
this.webhookAuth = webhookAuth;
|
|
@@ -215,24 +250,38 @@ class Team extends Resource {
|
|
|
215
250
|
zoneId: this.zoneId || null,
|
|
216
251
|
errorHandlerConfig: this.errorHandlerConfig || null,
|
|
217
252
|
// Kept in the given order, not sorted: the order is the inheritance precedence, so a pure
|
|
218
|
-
// reorder is a real change that must be detected and pushed.
|
|
219
|
-
|
|
253
|
+
// reorder is a real change that must be detected and pushed. Renamed from parentTeamSlugs
|
|
254
|
+
// when version pins arrived, so every workspace with parents reports settings.json modified
|
|
255
|
+
// once after upgrading — a deliberate one-time diff.
|
|
256
|
+
parentTeams: (this.parentTeams || []).map(({ slug, version }) => version ? { slug, version } : { slug }),
|
|
220
257
|
};
|
|
221
|
-
// Inserted only when set, so every
|
|
258
|
+
// Inserted only when set, so every settings.json that predates webhook auth keeps the
|
|
222
259
|
// hash already stored in .fcode and does not report a phantom conflict. A key present
|
|
223
260
|
// with an undefined value would not do: canonicalStringify writes that as null.
|
|
224
261
|
if (this.webhookAuth) {
|
|
225
262
|
payload.webhookAuth = this.webhookAuth;
|
|
226
263
|
}
|
|
227
|
-
// Same insert-only-when-set rule, for the same reason: a
|
|
264
|
+
// Same insert-only-when-set rule, for the same reason: a settings.json written before locales
|
|
228
265
|
// existed must keep the hash already stored in .fcode.
|
|
229
266
|
if (this.primaryLocale) {
|
|
230
267
|
payload.primaryLocale = this.primaryLocale;
|
|
231
268
|
}
|
|
269
|
+
// Versions hash only their tags and aliases their name->tag pairs: createdAt is
|
|
270
|
+
// server-assigned and a comment is immutable once published (there is no update mutation),
|
|
271
|
+
// so neither can represent a pushable local change. Inserted only when non-empty, again to
|
|
272
|
+
// keep hashes stored before versioning existed valid.
|
|
273
|
+
if (this.versions && this.versions.length > 0) {
|
|
274
|
+
payload.versions = this.versions.map(({ tag }) => tag).sort();
|
|
275
|
+
}
|
|
276
|
+
if (this.aliases && this.aliases.length > 0) {
|
|
277
|
+
payload.aliases = this.aliases
|
|
278
|
+
.map(({ name, tag }) => ({ name, tag }))
|
|
279
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
280
|
+
}
|
|
232
281
|
return (0, canonical_hash_1.canonicalJsonHash)(payload);
|
|
233
282
|
}
|
|
234
283
|
}
|
|
235
|
-
exports.
|
|
284
|
+
exports.WorkspaceSettings = WorkspaceSettings;
|
|
236
285
|
class ProcessNotFound extends Error {
|
|
237
286
|
}
|
|
238
287
|
exports.ProcessNotFound = ProcessNotFound;
|
|
@@ -251,6 +300,11 @@ exports.ResourceSlugArg = {
|
|
|
251
300
|
name: 'slug',
|
|
252
301
|
}),
|
|
253
302
|
};
|
|
303
|
+
exports.ShowInheritedFlag = {
|
|
304
|
+
showInherited: core_1.Flags.boolean({
|
|
305
|
+
description: 'Also list inherited resources that have no changes',
|
|
306
|
+
}),
|
|
307
|
+
};
|
|
254
308
|
exports.TeamNameArg = {
|
|
255
309
|
team: core_1.Args.string({ description: 'Team name', name: 'team' }),
|
|
256
310
|
};
|