@coalescesoftware/coa 1.0.102 → 1.0.114
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/bin/CLIProfile.js +20 -10
- package/bin/CommonCLI.js +17 -6
- package/bin/Deploy.js +1 -1
- package/bin/Package.js +731 -0
- package/bin/Plan.js +2 -2
- package/bin/RunOutput.js +82 -0
- package/bin/index.js +39 -17
- package/package.json +2 -2
package/bin/CLIProfile.js
CHANGED
|
@@ -55,6 +55,7 @@ exports.GetDefaultLocationForCoaConfigFile = GetDefaultLocationForCoaConfigFile;
|
|
|
55
55
|
exports.ICLIProfileExample = {
|
|
56
56
|
profile: "Profile To Use",
|
|
57
57
|
environmentID: "Environment ID",
|
|
58
|
+
parameters: "Parameters",
|
|
58
59
|
snowflakeAccount: "Snowflake Account To Use",
|
|
59
60
|
snowflakeAuthType: "Snowflake Auth Type (Basic, KeyPair)",
|
|
60
61
|
snowflakeKeyPairPath: "Snowflake Key Pair Path",
|
|
@@ -68,21 +69,29 @@ exports.ICLIProfileExample = {
|
|
|
68
69
|
exclude: "Coalesce Node Selector"
|
|
69
70
|
};
|
|
70
71
|
const ReadCLIProfiles = (filePath) => {
|
|
71
|
-
|
|
72
|
+
let filePathToUse;
|
|
73
|
+
if (!filePath) {
|
|
74
|
+
filePathToUse = (0, exports.GetDefaultLocationForCoaConfigFile)();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
filePathToUse = filePath;
|
|
78
|
+
}
|
|
79
|
+
return fs.promises.readFile(filePathToUse, 'utf-8')
|
|
80
|
+
.then((file) => {
|
|
72
81
|
return ini.parse(file);
|
|
73
|
-
})
|
|
82
|
+
})
|
|
83
|
+
.catch((err) => {
|
|
74
84
|
CLILogger.error("unable to read cli profile file filePath:", filePath, err);
|
|
75
|
-
|
|
85
|
+
if (!filePath) //if no filepath was specified, silently proceed
|
|
86
|
+
return {};
|
|
87
|
+
else //unable to proceed couldnt read file
|
|
88
|
+
throw new Error(`unable to read cli profile:${filePathToUse}`);
|
|
76
89
|
});
|
|
77
90
|
};
|
|
78
91
|
const GetFinalCLIProfile = (commandLineOverrides, configFileLocation) => {
|
|
79
92
|
let profileToUseOverride = commandLineOverrides.profile ? commandLineOverrides.profile : null;
|
|
80
|
-
return ReadCLIProfiles(configFileLocation)
|
|
81
|
-
|
|
82
|
-
}).catch((err) => {
|
|
83
|
-
//unable to read cli profiles
|
|
84
|
-
return {};
|
|
85
|
-
}).then((cliProfiles) => {
|
|
93
|
+
return ReadCLIProfiles(configFileLocation)
|
|
94
|
+
.then((cliProfiles) => {
|
|
86
95
|
const defaultCLIProfile = cliProfiles.default;
|
|
87
96
|
let finalCLIProfile = {};
|
|
88
97
|
//if theres a default cli profile, start with that
|
|
@@ -124,7 +133,8 @@ const GetCLIConfig = (commandLineOverrides, configFileLocation) => {
|
|
|
124
133
|
snowflakeRole: cliProfile.snowflakeRole,
|
|
125
134
|
snowflakeUsername: cliProfile.snowflakeUsername,
|
|
126
135
|
snowflakeWarehouse: cliProfile.snowflakeWarehouse
|
|
127
|
-
}
|
|
136
|
+
},
|
|
137
|
+
runtimeParameters: cliProfile.parameters,
|
|
128
138
|
};
|
|
129
139
|
Shared.Common.CleanupUndefinedValuesFromObject(cliConfig);
|
|
130
140
|
return cliConfig;
|
package/bin/CommonCLI.js
CHANGED
|
@@ -19,11 +19,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.GetUserConnectionForCLI = exports.CleanupCLIJob = void 0;
|
|
22
|
+
exports.FinishWithOutputFile = exports.GetUserConnectionForCLI = exports.CleanupCLIJob = void 0;
|
|
23
23
|
const Shared = __importStar(require("@coalescesoftware/shared"));
|
|
24
24
|
const fs = __importStar(require("fs"));
|
|
25
25
|
const crypto = __importStar(require("crypto"));
|
|
26
|
+
const RunOutput = __importStar(require("./RunOutput"));
|
|
26
27
|
const RunnerBackendLogger = Shared.Logging.GetLogger(Shared.Logging.LoggingArea.RunnerBackend);
|
|
28
|
+
const LogCLIInternal = Shared.Logging.GetLogger(Shared.Logging.LoggingArea.CLI_INTERNAL);
|
|
27
29
|
const CleanupCLIJob = (runCompletion, firebase, logContext, action) => {
|
|
28
30
|
const cleanupPromise = new Promise((resolve, reject) => {
|
|
29
31
|
let promiseError = null;
|
|
@@ -74,21 +76,20 @@ const GetKeyPairKey = (keyPairPath) => {
|
|
|
74
76
|
};
|
|
75
77
|
const GetUserConnectionForCLI = (userID, runInfo) => {
|
|
76
78
|
return new Promise((resolve, reject) => {
|
|
77
|
-
var _a, _b, _c, _d, _e, _f
|
|
79
|
+
var _a, _b, _c, _d, _e, _f;
|
|
78
80
|
const output = {
|
|
79
81
|
connectionDetails: {
|
|
80
82
|
userID,
|
|
81
83
|
user: (_a = runInfo.userCredentials) === null || _a === void 0 ? void 0 : _a.snowflakeUsername,
|
|
82
84
|
role: (_b = runInfo.userCredentials) === null || _b === void 0 ? void 0 : _b.snowflakeRole,
|
|
83
85
|
warehouse: (_c = runInfo.userCredentials) === null || _c === void 0 ? void 0 : _c.snowflakeWarehouse,
|
|
84
|
-
authenticator: (_d = runInfo.userCredentials) === null || _d === void 0 ? void 0 : _d.snowflakeAuthType
|
|
85
86
|
},
|
|
86
|
-
connectionType: (
|
|
87
|
+
connectionType: (_d = runInfo.userCredentials) === null || _d === void 0 ? void 0 : _d.snowflakeAuthType
|
|
87
88
|
};
|
|
88
|
-
if (!((
|
|
89
|
+
if (!((_e = runInfo.userCredentials) === null || _e === void 0 ? void 0 : _e.snowflakeAuthType)) {
|
|
89
90
|
reject(new Error("ERROR (GetUserConnectionForCLI): no auth type provided"));
|
|
90
91
|
}
|
|
91
|
-
else if (((
|
|
92
|
+
else if (((_f = runInfo.userCredentials) === null || _f === void 0 ? void 0 : _f.snowflakeAuthType) === Shared.ConnectionOperations.EUserConnectionTypes.keyPair) {
|
|
92
93
|
GetKeyPairKey(Shared.Common.getValueSafe(runInfo, ["userCredentials", "snowflakeKeyPairPath"], ""))
|
|
93
94
|
.then((keyPair) => {
|
|
94
95
|
output.connectionDetails.keyPair = keyPair;
|
|
@@ -104,4 +105,14 @@ const GetUserConnectionForCLI = (userID, runInfo) => {
|
|
|
104
105
|
});
|
|
105
106
|
};
|
|
106
107
|
exports.GetUserConnectionForCLI = GetUserConnectionForCLI;
|
|
108
|
+
const FinishWithOutputFile = (logContextToUse, outputFilePath, runCounter, token) => {
|
|
109
|
+
if (!outputFilePath) {
|
|
110
|
+
return Promise.resolve();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
LogCLIInternal.infoContext(logContextToUse, "saving run results to file", outputFilePath);
|
|
114
|
+
return RunOutput.SaveRunOutputToFile(outputFilePath, runCounter.toString(), token);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
exports.FinishWithOutputFile = FinishWithOutputFile;
|
|
107
118
|
//# sourceMappingURL=CommonCLI.js.map
|
package/bin/Deploy.js
CHANGED
|
@@ -50,7 +50,7 @@ const DeployWithCLI = (plan, config, token) => {
|
|
|
50
50
|
logContext = Shared.Logging.CreateLogContext(teamID, environmentID, userID);
|
|
51
51
|
const connectionCache = new Shared.Snowflake.ConnectionStorageClass();
|
|
52
52
|
RunSQL = Shared.SQLExecutorCreators.CreateRunSQLWithoutScheduler(teamDetails, connectionCache);
|
|
53
|
-
runInfo = Shared.DeployOperations.CreateDeployRequestObject(plan.plan, plan.environmentState, teamInfo, plan.gitInfo, plan.targetEnvironment,
|
|
53
|
+
runInfo = Shared.DeployOperations.CreateDeployRequestObject(plan.plan, plan.environmentState, teamInfo, plan.gitInfo, plan.targetEnvironment, plan.runtimeParameters);
|
|
54
54
|
runInfo.userCredentials = config.userCredentials;
|
|
55
55
|
return CommonCLI.GetUserConnectionForCLI(userID, runInfo);
|
|
56
56
|
})
|
package/bin/Package.js
ADDED
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.GetPackageSupportedEntityTypes = exports.RemoveNamespacedWorkspaceData_Testing = exports.NamespaceWorkspaceData_Testing = exports.UninstallPackage = exports.InstallPackage = exports.PackageProvider = exports.GetPackageListMessageCLI = exports.InitializePackageContext = exports.localInstallKeyword = void 0;
|
|
26
|
+
/* eslint-disable multiline-comment-style */
|
|
27
|
+
const Shared = __importStar(require("@coalescesoftware/shared"));
|
|
28
|
+
const fs_1 = __importDefault(require("fs"));
|
|
29
|
+
const os = require("os");
|
|
30
|
+
/**
|
|
31
|
+
* coa package uses the same config file that should be setup to leverage coa.
|
|
32
|
+
*
|
|
33
|
+
* project - the user's ws data
|
|
34
|
+
* package - the targetted repo being applied to the project
|
|
35
|
+
* dependency - any package installed to a project/another package
|
|
36
|
+
*
|
|
37
|
+
* coa add works at a high level in these steps:
|
|
38
|
+
* 1 - collects ws data from a targetted repo (local or remote)
|
|
39
|
+
* 2 - namespaces that ws data w/package ID
|
|
40
|
+
* 3 - adds to firestore packages collection the info for the package being installed (dependency information) w/status: 'adding'
|
|
41
|
+
* 4 - updates project ws data on firestore with namespaced ws data from package
|
|
42
|
+
* 5 - updates firestore package dependency information w/status: 'added' and a timestamp
|
|
43
|
+
* 6 - in case of error, will clean up any added package information including dependency info from project ws data on FS
|
|
44
|
+
*
|
|
45
|
+
* coa remove works similarly
|
|
46
|
+
*/
|
|
47
|
+
exports.localInstallKeyword = "file:";
|
|
48
|
+
const PackagesLogger = Shared.Logging.GetLogger(Shared.Logging.LoggingArea.CLI);
|
|
49
|
+
var EPackageStatus;
|
|
50
|
+
(function (EPackageStatus) {
|
|
51
|
+
EPackageStatus["adding"] = "adding";
|
|
52
|
+
EPackageStatus["added"] = "added";
|
|
53
|
+
EPackageStatus["removing"] = "removing";
|
|
54
|
+
EPackageStatus["error"] = "error";
|
|
55
|
+
})(EPackageStatus || (EPackageStatus = {}));
|
|
56
|
+
var EVersionType;
|
|
57
|
+
(function (EVersionType) {
|
|
58
|
+
EVersionType["file"] = "file";
|
|
59
|
+
EVersionType["url"] = "url";
|
|
60
|
+
})(EVersionType || (EVersionType = {}));
|
|
61
|
+
////////////////////////////////////////////////////////////////////
|
|
62
|
+
//////////////////// reusable namespacing helper functions
|
|
63
|
+
////////////////////////////////////////////////////////////////////
|
|
64
|
+
/**
|
|
65
|
+
* Recieves a string or a number that will be namespaced (NAMESPACEVALUE::STRINGorNUMBER)
|
|
66
|
+
* @param value
|
|
67
|
+
* @param namespace
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
const UpdateValueWithNamespace = (value, namespace) => {
|
|
71
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, typeof namespace === "string", `Namespace was not a string, but was type ${typeof namespace}`);
|
|
72
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, !!namespace.trim(), `Namespace cannot be an empty string`);
|
|
73
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, typeof value === "string" || typeof value === "number", `Value was not a string, but was type ${typeof value}`);
|
|
74
|
+
const stringValue = String(value);
|
|
75
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, stringValue.indexOf("::") === -1, `value to namespace contained invalid character ":"`);
|
|
76
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, namespace.indexOf("::") === -1, `namespace contained invalid character ":"`);
|
|
77
|
+
if (stringValue.trim() === "")
|
|
78
|
+
return stringValue; //empty string should not be namespaced but returned as is
|
|
79
|
+
return `${namespace}::${value}`;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Updates originalObject field values (fieldsToUpdate) using fieldValueUpdateCB and returns original value for non selected fields
|
|
83
|
+
*
|
|
84
|
+
* @param entity object with field values to update
|
|
85
|
+
* @param entityFieldsToUpdate an array of fields to update, or null to update all fields
|
|
86
|
+
* @param namespacerCB CB to call on each field to update
|
|
87
|
+
* @returns entity with field values that have been namespaced or updated with CB
|
|
88
|
+
*/
|
|
89
|
+
const EntityNamespacer = (entity, entityFieldsToUpdate, namespacerCB) => {
|
|
90
|
+
const updatedEntity = Object.assign({}, entity);
|
|
91
|
+
if (!entityFieldsToUpdate) {
|
|
92
|
+
// update all
|
|
93
|
+
Object.keys(entity).forEach(field => {
|
|
94
|
+
updatedEntity[field] = namespacerCB(updatedEntity[field]);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
Object.keys(entity).forEach(key => {
|
|
99
|
+
// if key included in keypath array, update, otherwise return original value
|
|
100
|
+
if (entityFieldsToUpdate.includes(key)) {
|
|
101
|
+
updatedEntity[key] = namespacerCB(updatedEntity[key]);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
updatedEntity[key] = entity[key];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return updatedEntity;
|
|
109
|
+
};
|
|
110
|
+
////////////////////////////////////////////////////////////////////
|
|
111
|
+
///////////////// Parent namespacing functions
|
|
112
|
+
////////////////////////////////////////////////////////////////////
|
|
113
|
+
/**
|
|
114
|
+
* internal functions that will add or remove namespaced package data
|
|
115
|
+
* to/from a project's ws data and return the modified workspace data
|
|
116
|
+
*/
|
|
117
|
+
/**
|
|
118
|
+
* function adds namespaced package data to workspace data and return the modified workspace data
|
|
119
|
+
*
|
|
120
|
+
* @param allWorkspaceData
|
|
121
|
+
* @param packageInfo
|
|
122
|
+
* @param packageContext
|
|
123
|
+
* @returns AllWorkspaceData with added namespaced data
|
|
124
|
+
*/
|
|
125
|
+
const GetNamespacedWorkspaceData = (allWorkspaceData, packageInfo, packageContext) => {
|
|
126
|
+
const { id, version } = packageInfo;
|
|
127
|
+
const namespacedWorkspaceData = {};
|
|
128
|
+
Object.keys(allWorkspaceData).forEach(wsKey => {
|
|
129
|
+
try {
|
|
130
|
+
if (WorkspaceEntityNamespaceFunctionLookup[wsKey]) {
|
|
131
|
+
PackagesLogger.info(`Preparing workspace data for import: ${wsKey}`);
|
|
132
|
+
namespacedWorkspaceData[wsKey] = WorkspaceEntityNamespaceFunctionLookup[wsKey].add(id, version, allWorkspaceData[wsKey]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const message = `error when preparing workspace data for import: ${wsKey}`;
|
|
137
|
+
if (error instanceof Error) {
|
|
138
|
+
PackagesLogger.errorContext(packageContext.loggerContext, message, error.message, error.name, error.stack, error);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
PackagesLogger.errorContext(packageContext.loggerContext, message, error);
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return namespacedWorkspaceData;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* will remove namespaced package workspace data from allWorkspaceData and return the updated object
|
|
150
|
+
*
|
|
151
|
+
* @param allWorkspaceData
|
|
152
|
+
* @param packageInfo
|
|
153
|
+
* @param packageContext
|
|
154
|
+
* @returns AllWorkspaceData with added namespaced data
|
|
155
|
+
*/
|
|
156
|
+
const RemoveNamespacedWorkspaceData = (allWorkspaceData, packageInfo, packageContext) => {
|
|
157
|
+
const prunedWorkspaceData = {};
|
|
158
|
+
const { id } = packageInfo;
|
|
159
|
+
Object.keys(allWorkspaceData).forEach(wsKey => {
|
|
160
|
+
try {
|
|
161
|
+
// if included in entities that should be imported, then add with namespace
|
|
162
|
+
if (WorkspaceEntityNamespaceFunctionLookup[wsKey]) {
|
|
163
|
+
PackagesLogger.info(`Pruning workspace data: ${wsKey}`);
|
|
164
|
+
prunedWorkspaceData[wsKey] = WorkspaceEntityNamespaceFunctionLookup[wsKey].remove(id, allWorkspaceData[wsKey]);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// else just add back the original data
|
|
168
|
+
prunedWorkspaceData[wsKey] = allWorkspaceData[wsKey];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const message = `error when pruning workspace data for: ${wsKey}`;
|
|
173
|
+
if (error instanceof Error) {
|
|
174
|
+
PackagesLogger.errorContext(packageContext.loggerContext, message, error.message, error.name, error.stack, error);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
PackagesLogger.errorContext(packageContext.loggerContext, message, error);
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return prunedWorkspaceData;
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Takes a parentEntityObject (ie 'stepTypes') that contains nested entity objects (ie 'stepType-1') that will be namespaced
|
|
186
|
+
* a) all nested entity object keys will be namespaced
|
|
187
|
+
* b) all nested entity object field values (fieldsToUpdate) will be namespaced
|
|
188
|
+
* c) (optional) additional work can be done on the newly namespaced nested entity object using the nestedObjectUpdateCB
|
|
189
|
+
*
|
|
190
|
+
* @param parentEntityObject object containing nested entity objects which will be iterated through and namespaced
|
|
191
|
+
* @param packageID used as new namespace
|
|
192
|
+
* @param fieldsToUpdate array of fields whose values will be namespaced for each nested entity object, or null to update all fields
|
|
193
|
+
* @param nestedObjectUpdateCB (optional) any additional work that should be done to namespaced nested entity object
|
|
194
|
+
* @param entity the entity (singular) being updated, ie. "step type" or "folder", etc. used for info logger
|
|
195
|
+
* @returns
|
|
196
|
+
*/
|
|
197
|
+
const NamespaceEntity = (parentEntityObject, packageID, packageVersion, fieldsToUpdate, nestedObjectUpdateCB, entity) => {
|
|
198
|
+
const namespacedDataObject = {};
|
|
199
|
+
Object.keys(parentEntityObject).forEach(key => {
|
|
200
|
+
const isPackageImportedObject = !!Shared.Common.getValueSafe(parentEntityObject[key], ["packageInfo", "id"], null);
|
|
201
|
+
if (isPackageImportedObject)
|
|
202
|
+
return; // do not namespace already namespaced data
|
|
203
|
+
const namespacedKey = UpdateValueWithNamespace(key, packageID);
|
|
204
|
+
PackagesLogger.info(`Adding ${entity}: ${key} as ${namespacedKey}`);
|
|
205
|
+
namespacedDataObject[namespacedKey] = Object.assign({}, EntityNamespacer(parentEntityObject[key], fieldsToUpdate, (fieldValueToUpdate) => UpdateValueWithNamespace(fieldValueToUpdate, packageID)));
|
|
206
|
+
// do additional work if needed on newly namespaced nested object
|
|
207
|
+
if (nestedObjectUpdateCB) {
|
|
208
|
+
nestedObjectUpdateCB(namespacedDataObject[namespacedKey], key);
|
|
209
|
+
}
|
|
210
|
+
// add package information to top level of entity
|
|
211
|
+
namespacedDataObject[namespacedKey]["packageInfo"] = BuildPackageInfoForEntity(packageID, packageVersion);
|
|
212
|
+
});
|
|
213
|
+
return namespacedDataObject;
|
|
214
|
+
};
|
|
215
|
+
////////////////////////////////////////////////////////////////////
|
|
216
|
+
///////////////// Namespacing function dictionary
|
|
217
|
+
////////////////////////////////////////////////////////////////////
|
|
218
|
+
// to start packages will support import/removal of macros and steptypes
|
|
219
|
+
const WorkspaceEntityNamespaceFunctionLookup = {
|
|
220
|
+
macros: {
|
|
221
|
+
add: (packageID, packageVersion, macros) => MacrosNamespacer(packageID, macros, packageVersion),
|
|
222
|
+
remove: (packageID, macros) => MacrosNamespaceRemover(packageID, macros)
|
|
223
|
+
},
|
|
224
|
+
stepTypes: {
|
|
225
|
+
add: (packageID, packageVersion, stepTypes) => StepTypesNamespacer(packageID, stepTypes, packageVersion),
|
|
226
|
+
remove: (packageID, stepTypes) => StepTypesNamespaceRemover(packageID, stepTypes)
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
////////////////////////////////////////////////////////////////////
|
|
230
|
+
///////////////// Workspace Data Namespacing functions by entity (adding)
|
|
231
|
+
////////////////////////////////////////////////////////////////////
|
|
232
|
+
const MacrosNamespacer = (packageID, macros, packageVersion) => {
|
|
233
|
+
return NamespaceEntity(macros, packageID, packageVersion, ["id"], null, "macro");
|
|
234
|
+
};
|
|
235
|
+
const StepTypesNamespacer = (packageID, stepTypes, packageVersion) => {
|
|
236
|
+
const filteredStepTypes = Object.keys(stepTypes)
|
|
237
|
+
.filter(stepTypeID => !Shared.StepTypes.isDefaultStepType(stepTypeID)) // remove default steptypes
|
|
238
|
+
.reduce((acc, id) => {
|
|
239
|
+
acc[id] = stepTypes[id];
|
|
240
|
+
return acc;
|
|
241
|
+
}, {});
|
|
242
|
+
const updateStepTypeCB = (namespacedStepTypeData) => {
|
|
243
|
+
namespacedStepTypeData.metadata["defaultStorageLocation"] = null;
|
|
244
|
+
};
|
|
245
|
+
return NamespaceEntity(filteredStepTypes, packageID, packageVersion, ["id"], updateStepTypeCB, "stepType");
|
|
246
|
+
};
|
|
247
|
+
////////////////////////////////////////////////////////////////////
|
|
248
|
+
///////////////// Workspace Data Namespace Remover functions by entity (remove)
|
|
249
|
+
////////////////////////////////////////////////////////////////////
|
|
250
|
+
const EntityRemover = (packageID, parentEntityObject, entityName) => {
|
|
251
|
+
const prunedEntityObject = {};
|
|
252
|
+
Object.keys(parentEntityObject)
|
|
253
|
+
.filter(entityKey => {
|
|
254
|
+
const entityPackageInfo = Shared.Common.getValueSafe(parentEntityObject[entityKey], ["packageInfo"], null);
|
|
255
|
+
// if no info, then not imported, if info doesn't match, then not imported from this package
|
|
256
|
+
if (!entityPackageInfo || (!!entityPackageInfo && entityPackageInfo.id !== packageID)) {
|
|
257
|
+
return entityKey;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
PackagesLogger.info(`Removing ${entityName}: ${entityKey}`);
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
.forEach(prunedEntityKey => prunedEntityObject[prunedEntityKey] = parentEntityObject[prunedEntityKey]);
|
|
264
|
+
return prunedEntityObject;
|
|
265
|
+
};
|
|
266
|
+
const MacrosNamespaceRemover = (packageID, macros) => {
|
|
267
|
+
return EntityRemover(packageID, macros, "macro");
|
|
268
|
+
};
|
|
269
|
+
const StepTypesNamespaceRemover = (packageID, stepTypes) => {
|
|
270
|
+
return EntityRemover(packageID, stepTypes, "step type");
|
|
271
|
+
};
|
|
272
|
+
////////////////////////////////////////////////////////////////////
|
|
273
|
+
///////////////// Package/Dependency getters/builders
|
|
274
|
+
////////////////////////////////////////////////////////////////////
|
|
275
|
+
const BuildPackageInfoForEntity = (packageID, version) => {
|
|
276
|
+
return {
|
|
277
|
+
id: packageID,
|
|
278
|
+
version
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
const InitializePackageDependencyInfoForPackage = (id, versionInfo, version, userID) => {
|
|
282
|
+
return {
|
|
283
|
+
id,
|
|
284
|
+
version,
|
|
285
|
+
versionInfo,
|
|
286
|
+
status: EPackageStatus.adding,
|
|
287
|
+
createdAt: null,
|
|
288
|
+
addedBy: userID
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
////////////////////////////////////////////////////////////////////
|
|
292
|
+
///////////////// Workspace Data Collection functions
|
|
293
|
+
////////////////////////////////////////////////////////////////////
|
|
294
|
+
const GetRepoNameFromURL = (repoURL) => {
|
|
295
|
+
try {
|
|
296
|
+
const nameIndex = repoURL.lastIndexOf("/") + 1;
|
|
297
|
+
const gitIndex = repoURL.lastIndexOf(".git");
|
|
298
|
+
return repoURL.substring(nameIndex, gitIndex);
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
PackagesLogger.error(`Error when reading package dependency URL: ${repoURL}`, error);
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
const GetAllWorkspaceDataAndCommitHashFromRemoteRepository = (location) => {
|
|
306
|
+
return new Promise((resolve, reject) => {
|
|
307
|
+
// ensure a unique temp folder name
|
|
308
|
+
const tempRepoFolder = `COA_TEMP_${GetRepoNameFromURL(location)}_${Math.random()}`;
|
|
309
|
+
const tempFolderPath = os.tmpdir();
|
|
310
|
+
let commitHashToReturn;
|
|
311
|
+
let commitOrBranch = null;
|
|
312
|
+
let locationToUse = location;
|
|
313
|
+
const indexOfHash = location.indexOf("#");
|
|
314
|
+
// if hash indicator, then grab commit and remove #info from URL
|
|
315
|
+
if (indexOfHash > -1) {
|
|
316
|
+
commitOrBranch = location.slice(indexOfHash + 1);
|
|
317
|
+
locationToUse = location.substring(0, indexOfHash);
|
|
318
|
+
}
|
|
319
|
+
const toExecute = commitOrBranch ? `&& git checkout ${commitOrBranch} && git log -n 1 ${commitOrBranch}` : `&& git log -n 1`;
|
|
320
|
+
PackagesLogger.info(`Cloning Coalesce package from repo URL: ${locationToUse}`);
|
|
321
|
+
return Shared.Common.executeCommand(`cd ${tempFolderPath} && git clone ${locationToUse} ${tempRepoFolder} && ls && cd ${tempRepoFolder} && ls ${toExecute}`)
|
|
322
|
+
.then(res => {
|
|
323
|
+
const fileSystemSettings = { fs: fs_1.default, dir: `${tempFolderPath}/${tempRepoFolder}` };
|
|
324
|
+
const getCommitFromGitLogRegex = new RegExp(/commit ([\s\S]*?)\n/);
|
|
325
|
+
const regexResult = getCommitFromGitLogRegex.exec(res[0]);
|
|
326
|
+
if (!regexResult) {
|
|
327
|
+
const message = `No commit was found for ${commitOrBranch}`;
|
|
328
|
+
throw new Error(message);
|
|
329
|
+
}
|
|
330
|
+
commitHashToReturn = regexResult[1];
|
|
331
|
+
return GetAllWorkspaceDataFromFileSystem(fileSystemSettings);
|
|
332
|
+
})
|
|
333
|
+
.then((workspaceData) => {
|
|
334
|
+
const additionalLogInfo = commitOrBranch ? ` at commit or branch: "${commitOrBranch}"` : "";
|
|
335
|
+
PackagesLogger.info(`Reading data from Coalesce package ${workspaceData.projectName || GetRepoNameFromURL(locationToUse)}${additionalLogInfo}...`);
|
|
336
|
+
resolve({
|
|
337
|
+
workspaceData,
|
|
338
|
+
hashFromRemote: commitHashToReturn
|
|
339
|
+
});
|
|
340
|
+
})
|
|
341
|
+
.catch(error => {
|
|
342
|
+
PackagesLogger.error(`Error while collecting workspace data for repo ${GetRepoNameFromURL(locationToUse)}`, error);
|
|
343
|
+
reject(error);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
const GetAllWorkspaceDataFromFileSystem = (fileSystemSettings) => {
|
|
348
|
+
return Shared.Workspaces.GetAllWorkspaceDataFromGitCommit(fileSystemSettings, null, null);
|
|
349
|
+
};
|
|
350
|
+
////////////////////////////////////////////////////////////////////
|
|
351
|
+
///////////////// Other helpers
|
|
352
|
+
////////////////////////////////////////////////////////////////////
|
|
353
|
+
/**
|
|
354
|
+
* this function will remove any ws data associated with packageInfo from projectWorkspaceData
|
|
355
|
+
* before reinstalling to ensure up-to-date package information
|
|
356
|
+
*
|
|
357
|
+
* @param packageInfo
|
|
358
|
+
* @param packageWorkspaceData
|
|
359
|
+
* @param projectWorkspaceData
|
|
360
|
+
* @param packageContext
|
|
361
|
+
* @returns {
|
|
362
|
+
* desiredState: what FS should look like
|
|
363
|
+
* stateToReplace: what FS looks like now
|
|
364
|
+
* }
|
|
365
|
+
*/
|
|
366
|
+
const GetNamespacedDataAndDesiredStateForFSFlush = (packageInfo, packageWorkspaceData, projectWorkspaceData, packageContext) => {
|
|
367
|
+
if (!packageInfo.id) {
|
|
368
|
+
const message = `PackageID was ${packageInfo.id} when it should be a string`;
|
|
369
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, false, message);
|
|
370
|
+
throw new Error(message);
|
|
371
|
+
}
|
|
372
|
+
PackagesLogger.info(`Cleaning up any stale package data in your project...`);
|
|
373
|
+
// remove entities that were installed by current package
|
|
374
|
+
const prunedProjectWorkspaceData = RemoveNamespacedWorkspaceData(projectWorkspaceData, packageInfo, packageContext);
|
|
375
|
+
// get namespaced data for current package
|
|
376
|
+
const namespacedDataFromPackage = GetNamespacedWorkspaceData(packageWorkspaceData, packageInfo, packageContext);
|
|
377
|
+
// add namespaced data to project data
|
|
378
|
+
const projectWorkspaceDataWithUpdates = CombineWorkspaceDataByEntities(namespacedDataFromPackage, prunedProjectWorkspaceData);
|
|
379
|
+
return {
|
|
380
|
+
desiredState: projectWorkspaceDataWithUpdates,
|
|
381
|
+
namespacedData: namespacedDataFromPackage
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
// get a package context object utilized by much of the functionality in this file
|
|
385
|
+
const InitializePackageContext = (authInfo, environmentID) => {
|
|
386
|
+
return {
|
|
387
|
+
firestore: authInfo.firebase.firestore(),
|
|
388
|
+
timestamp: Shared.Firebase.serverTimestamp,
|
|
389
|
+
teamID: authInfo.teamInfo.fbTeamID,
|
|
390
|
+
environmentID,
|
|
391
|
+
loggerContext: { orgID: authInfo.teamInfo.fbTeamID, userID: authInfo.teamInfo.fbUserID }
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
exports.InitializePackageContext = InitializePackageContext;
|
|
395
|
+
const CombineWorkspaceDataByEntities = (namespacedWorkspaceData, projectWorkspaceData) => {
|
|
396
|
+
let updatedProjectWorkspaceData = {};
|
|
397
|
+
Object.keys(projectWorkspaceData).forEach(entityKey => {
|
|
398
|
+
updatedProjectWorkspaceData[entityKey] = projectWorkspaceData[entityKey];
|
|
399
|
+
});
|
|
400
|
+
Object.keys(namespacedWorkspaceData).forEach(entityKey => {
|
|
401
|
+
updatedProjectWorkspaceData[entityKey] = Object.assign(Object.assign({}, updatedProjectWorkspaceData[entityKey]), namespacedWorkspaceData[entityKey]);
|
|
402
|
+
});
|
|
403
|
+
return updatedProjectWorkspaceData;
|
|
404
|
+
};
|
|
405
|
+
const InitializeVersionInfo = (commitOrBranch, repoLocation) => {
|
|
406
|
+
if (!!commitOrBranch) {
|
|
407
|
+
return {
|
|
408
|
+
commit: commitOrBranch,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
return {
|
|
413
|
+
filePath: repoLocation,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
const BuildManifest = (workspaceData) => {
|
|
418
|
+
const manifest = {};
|
|
419
|
+
const getEntityNameFromPackageManifest = (entityType, entityID) => {
|
|
420
|
+
return Shared.Common.getValueSafe(workspaceData, [entityType, entityID, "name"], entityID);
|
|
421
|
+
};
|
|
422
|
+
Object.keys(workspaceData).forEach(entityType => {
|
|
423
|
+
const entityImportedData = Object.keys(workspaceData[entityType]);
|
|
424
|
+
manifest[entityType] = {};
|
|
425
|
+
entityImportedData.forEach(namedEntityKey => {
|
|
426
|
+
debugger;
|
|
427
|
+
manifest[entityType][namedEntityKey] = {
|
|
428
|
+
id: namedEntityKey,
|
|
429
|
+
name: getEntityNameFromPackageManifest(entityType, namedEntityKey)
|
|
430
|
+
};
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
return manifest;
|
|
434
|
+
};
|
|
435
|
+
////////////////////////////////////////////////////
|
|
436
|
+
///////////// Firestore read/write funcs
|
|
437
|
+
////////////////////////////////////////////////////
|
|
438
|
+
const GetPackageDocRefAdmin = (packageInfo, packageContext) => {
|
|
439
|
+
const { environmentID, teamID, firestore } = packageContext;
|
|
440
|
+
return Shared.CommonOperations.getOrgConfigDocRefAdmin(firestore, teamID).collection("workspaces").doc(environmentID.toString()).collection("packages").doc(packageInfo.id);
|
|
441
|
+
};
|
|
442
|
+
const UpdatePackageInformationFS = (packageInfo, status, packageContext, setTimestamp) => {
|
|
443
|
+
// example: setting timestamp once package has completed install
|
|
444
|
+
const createdAt = setTimestamp ? packageContext.timestamp : packageInfo.createdAt;
|
|
445
|
+
const update = Object.assign({}, Object.assign(Object.assign({}, packageInfo), { status, createdAt }));
|
|
446
|
+
return GetPackageDocRefAdmin(packageInfo, packageContext).set(update)
|
|
447
|
+
.then(() => {
|
|
448
|
+
return { status, id: packageInfo.id };
|
|
449
|
+
});
|
|
450
|
+
};
|
|
451
|
+
const RemovePackageInformationFS = (packageInfo, packageContext) => {
|
|
452
|
+
const { environmentID, teamID, firestore } = packageContext;
|
|
453
|
+
return Shared.CommonOperations.getOrgConfigDocRefAdmin(firestore, teamID).collection("workspaces").doc(environmentID.toString()).collection("packages").doc(packageInfo.id).delete();
|
|
454
|
+
};
|
|
455
|
+
const GetPackageListMessageCLI = (packageContext) => {
|
|
456
|
+
const { environmentID, teamID, firestore } = packageContext;
|
|
457
|
+
return Shared.Workspaces.getAllWorkspaceDataFromFirebase(firestore, teamID, environmentID)
|
|
458
|
+
.then(wsData => {
|
|
459
|
+
const packages = Shared.Common.getValueSafe(wsData, ["packages"], null);
|
|
460
|
+
if (packages && Object.keys(packages).length) {
|
|
461
|
+
const listForCLI = Object.keys(packages).map(packageID => `${packageID} \n`);
|
|
462
|
+
listForCLI.unshift(`\nPackages added to environment ${environmentID}: \n`);
|
|
463
|
+
return listForCLI.join("");
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
return `No packages added to environment ${environmentID}`;
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
exports.GetPackageListMessageCLI = GetPackageListMessageCLI;
|
|
471
|
+
//////////////////////////////////////////////////////////
|
|
472
|
+
///////////// install/remove kickoff functions and classes
|
|
473
|
+
//////////////////////////////////////////////////////////
|
|
474
|
+
class PackageProvider {
|
|
475
|
+
constructor(dirOrURL, loggerContext) {
|
|
476
|
+
this.version = dirOrURL;
|
|
477
|
+
this.loggerContext = loggerContext;
|
|
478
|
+
// these vars will be null until getWorkspaceDataFS is called
|
|
479
|
+
this.commitHash = null;
|
|
480
|
+
this.id = null;
|
|
481
|
+
this.workspaceData = null;
|
|
482
|
+
this.versionInfo = null;
|
|
483
|
+
// init logic
|
|
484
|
+
if (!(typeof this.version === "string")) {
|
|
485
|
+
const message = `Location should be a string, but is of type ${typeof this.version}`;
|
|
486
|
+
PackagesLogger.errorContext(this.loggerContext, message);
|
|
487
|
+
throw new Error(`Invalid Package package location: ${message}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
_getVersionType() {
|
|
491
|
+
const fileKeywordIndex = this.version.indexOf(exports.localInstallKeyword);
|
|
492
|
+
const httpIndex = this.version.indexOf("http");
|
|
493
|
+
if (fileKeywordIndex === 0) {
|
|
494
|
+
return EVersionType.file;
|
|
495
|
+
}
|
|
496
|
+
else if (httpIndex === 0) {
|
|
497
|
+
return EVersionType.url;
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
const message = `Error with URL or filepath: "${this.version}" - filepath missing prefix "filepath:" or URL missing "http://" or "https://"`;
|
|
501
|
+
PackagesLogger.errorContext(this.loggerContext, message);
|
|
502
|
+
throw new Error(message);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
_isProjectNameValid(name) {
|
|
506
|
+
let isValid = true;
|
|
507
|
+
const indexOfNamespace = name.indexOf("::");
|
|
508
|
+
// projectName should not be only whitespace
|
|
509
|
+
if (indexOfNamespace > -1) {
|
|
510
|
+
isValid = false;
|
|
511
|
+
}
|
|
512
|
+
return isValid;
|
|
513
|
+
}
|
|
514
|
+
getWorkspaceDataFS() {
|
|
515
|
+
const versionType = this._getVersionType();
|
|
516
|
+
let wsDataFunc;
|
|
517
|
+
switch (versionType) {
|
|
518
|
+
case EVersionType.file: {
|
|
519
|
+
const dirWithoutKeyword = this.version.substring(exports.localInstallKeyword.length);
|
|
520
|
+
const fsSettings = { fs: fs_1.default, dir: dirWithoutKeyword };
|
|
521
|
+
this.commitHash = null;
|
|
522
|
+
wsDataFunc = GetAllWorkspaceDataFromFileSystem(fsSettings);
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
case EVersionType.url: {
|
|
526
|
+
wsDataFunc = GetAllWorkspaceDataAndCommitHashFromRemoteRepository(this.version)
|
|
527
|
+
.then((response) => {
|
|
528
|
+
const { workspaceData, hashFromRemote } = response;
|
|
529
|
+
this.commitHash = hashFromRemote;
|
|
530
|
+
return workspaceData;
|
|
531
|
+
});
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
default: {
|
|
535
|
+
const message = `versionType was invariant: ${versionType}`;
|
|
536
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, false, message);
|
|
537
|
+
throw new Error(message);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return wsDataFunc
|
|
541
|
+
.then((workspaceData) => {
|
|
542
|
+
// ensure package ID
|
|
543
|
+
if (!workspaceData.projectName) {
|
|
544
|
+
PackagesLogger.errorContext(this.loggerContext, `Invalid Package: Missing project name`);
|
|
545
|
+
PackagesLogger.errorContext(this.loggerContext, `Package owner must add a project name in Coalesce git settings before deploying commit for Package`);
|
|
546
|
+
throw new Error(`Invalid Package: Missing package ID; Package owner must add a package name in Coalesce git settings before deploying commit for Package`);
|
|
547
|
+
}
|
|
548
|
+
// validate project name
|
|
549
|
+
if (!this._isProjectNameValid(workspaceData.projectName)) {
|
|
550
|
+
PackagesLogger.errorContext(this.loggerContext, `Invalid Package: Project name contains reserved namespacing characters "::"`);
|
|
551
|
+
throw new Error(`${workspaceData.projectName} contains "::" and is not a valid project name`);
|
|
552
|
+
}
|
|
553
|
+
this.id = workspaceData.projectName.toUpperCase(); // should be uppercase
|
|
554
|
+
this.workspaceData = workspaceData;
|
|
555
|
+
this.versionInfo = InitializeVersionInfo(this.commitHash, this.version);
|
|
556
|
+
return this.workspaceData;
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
exports.PackageProvider = PackageProvider;
|
|
561
|
+
const InstallPackage = (packageProvider, packageContext) => {
|
|
562
|
+
const { firestore, teamID, environmentID, loggerContext } = packageContext;
|
|
563
|
+
return new Promise((resolve, reject) => {
|
|
564
|
+
let projectWorkspaceData;
|
|
565
|
+
let packageDependencyInfo;
|
|
566
|
+
let manifest;
|
|
567
|
+
PackagesLogger.infoContext(loggerContext, `Gathering your project workspace data for environment: ${environmentID}`);
|
|
568
|
+
return Shared.Workspaces.getAllWorkspaceDataFromFirebase(firestore, teamID, environmentID)
|
|
569
|
+
.then((projectWorkspaceDataFromFirestore) => {
|
|
570
|
+
projectWorkspaceData = projectWorkspaceDataFromFirestore;
|
|
571
|
+
return packageProvider.getWorkspaceDataFS();
|
|
572
|
+
})
|
|
573
|
+
.then(() => {
|
|
574
|
+
const { id, versionInfo } = packageProvider; // at this point these vars have been defined
|
|
575
|
+
if (!versionInfo) {
|
|
576
|
+
const message = `versionInfo was ${versionInfo}`;
|
|
577
|
+
Shared.Common.assert(Shared.Logging.LoggingArea.Packages, false, message);
|
|
578
|
+
throw new Error(message);
|
|
579
|
+
}
|
|
580
|
+
PackagesLogger.infoContext(loggerContext, `Installing package using namespace "${id}::"`);
|
|
581
|
+
packageDependencyInfo = InitializePackageDependencyInfoForPackage(id, versionInfo, packageProvider.version, loggerContext.userID || "unknown");
|
|
582
|
+
return UpdatePackageInformationFS(packageDependencyInfo, EPackageStatus.adding, packageContext, false);
|
|
583
|
+
})
|
|
584
|
+
.then((packageInfoFS) => {
|
|
585
|
+
const { status, id } = packageInfoFS;
|
|
586
|
+
PackagesLogger.infoContext(loggerContext, `${status} ${id}...building firestore updates payload...`);
|
|
587
|
+
const { desiredState, namespacedData } = GetNamespacedDataAndDesiredStateForFSFlush(packageDependencyInfo, packageProvider.workspaceData, projectWorkspaceData, packageContext);
|
|
588
|
+
manifest = BuildManifest(namespacedData);
|
|
589
|
+
PackagesLogger.infoContext(loggerContext, "Applying updates to firestore...");
|
|
590
|
+
return Shared.Workspaces.FlushFirestoreWorkspaceWithAllWorkspaceData(firestore, teamID, environmentID, desiredState, projectWorkspaceData);
|
|
591
|
+
})
|
|
592
|
+
.then(() => {
|
|
593
|
+
return UpdatePackageInformationFS(Object.assign(Object.assign({}, packageDependencyInfo), { manifest }), EPackageStatus.added, packageContext, true);
|
|
594
|
+
})
|
|
595
|
+
.then((packageInfoFS) => {
|
|
596
|
+
const { status, id } = packageInfoFS;
|
|
597
|
+
PackagesLogger.infoContext(loggerContext, `${status} ${id}...update successful!`);
|
|
598
|
+
resolve();
|
|
599
|
+
})
|
|
600
|
+
.catch(error => {
|
|
601
|
+
if (!!packageDependencyInfo) {
|
|
602
|
+
return UpdatePackageInformationFS(packageDependencyInfo, EPackageStatus.error, packageContext, false)
|
|
603
|
+
.then((packageInfo) => {
|
|
604
|
+
const { status, id } = packageInfo;
|
|
605
|
+
PackagesLogger.errorContext(loggerContext, `Update failed for ${id}. Package ${id} status: ${status}, removing package information from project: `, error);
|
|
606
|
+
PackagesLogger.errorContext(loggerContext, error);
|
|
607
|
+
return (0, exports.UninstallPackage)(id, packageContext);
|
|
608
|
+
})
|
|
609
|
+
.then(() => {
|
|
610
|
+
const message = `All data from package ${packageDependencyInfo.id} removed from project after error during installation.`;
|
|
611
|
+
PackagesLogger.infoContext(loggerContext, message);
|
|
612
|
+
resolve();
|
|
613
|
+
})
|
|
614
|
+
.catch(error => reject(error));
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
PackagesLogger.errorContext(loggerContext, `Update failed when installing package from ${packageProvider.version}`, error);
|
|
618
|
+
reject(error);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
};
|
|
623
|
+
exports.InstallPackage = InstallPackage;
|
|
624
|
+
const UninstallPackage = (packageID, packageContext) => {
|
|
625
|
+
const { firestore, teamID, environmentID, loggerContext } = packageContext;
|
|
626
|
+
return new Promise((resolve, reject) => {
|
|
627
|
+
let projectWorkspaceData;
|
|
628
|
+
let prunedWorkspaceData;
|
|
629
|
+
PackagesLogger.infoContext(loggerContext, `Gathering your project workspace data for environment: ${environmentID}`);
|
|
630
|
+
return Shared.Workspaces.getAllWorkspaceDataFromFirebase(firestore, teamID, environmentID)
|
|
631
|
+
.then((projectWorkspaceDataFromFirestore) => {
|
|
632
|
+
projectWorkspaceData = projectWorkspaceDataFromFirestore;
|
|
633
|
+
const allProjectDependencies = Shared.Common.getValueSafe(projectWorkspaceDataFromFirestore, ["packages"], {});
|
|
634
|
+
const thisDependencyInfo = allProjectDependencies[packageID];
|
|
635
|
+
if (!thisDependencyInfo) {
|
|
636
|
+
const depKeys = Object.keys(allProjectDependencies);
|
|
637
|
+
reject(new Error(`Environment ${environmentID} has ${depKeys.length} packages installed: ${depKeys}. Package "${packageID}" is not installed to this environment.`));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
PackagesLogger.infoContext(loggerContext, `Removing package workspace data from your project`);
|
|
641
|
+
prunedWorkspaceData = RemoveNamespacedWorkspaceData(projectWorkspaceData, thisDependencyInfo, packageContext);
|
|
642
|
+
return UpdatePackageInformationFS(thisDependencyInfo, EPackageStatus.removing, packageContext, false)
|
|
643
|
+
.then(() => {
|
|
644
|
+
PackagesLogger.infoContext(loggerContext, `Applying updates to firestore...`);
|
|
645
|
+
return Shared.Workspaces.FlushFirestoreWorkspaceWithAllWorkspaceData(firestore, teamID, environmentID, prunedWorkspaceData, projectWorkspaceData);
|
|
646
|
+
})
|
|
647
|
+
.then(() => {
|
|
648
|
+
return RemovePackageInformationFS(thisDependencyInfo, packageContext);
|
|
649
|
+
})
|
|
650
|
+
.then(() => {
|
|
651
|
+
PackagesLogger.infoContext(loggerContext, `Removed ${packageID} workspace data from your project`);
|
|
652
|
+
resolve();
|
|
653
|
+
})
|
|
654
|
+
.catch((error) => {
|
|
655
|
+
if (!!thisDependencyInfo) {
|
|
656
|
+
return UpdatePackageInformationFS(thisDependencyInfo, EPackageStatus.error, packageContext, false)
|
|
657
|
+
.then(() => {
|
|
658
|
+
PackagesLogger.errorContext(loggerContext, `Encountered a problem when removing ${thisDependencyInfo.id}, removal aborted. Please try again.`);
|
|
659
|
+
reject(error);
|
|
660
|
+
})
|
|
661
|
+
.catch(error => reject(error));
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
PackagesLogger.errorContext(loggerContext, `Update failed when removing package`, error);
|
|
665
|
+
reject(error);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
exports.UninstallPackage = UninstallPackage;
|
|
672
|
+
////////////////////////////////////////////////////
|
|
673
|
+
///////////// helper Jest test funcs
|
|
674
|
+
////////////////////////////////////////////////////
|
|
675
|
+
const NamespaceWorkspaceData_Testing = (allWorkspaceData, packageInfo) => {
|
|
676
|
+
const { id, version } = packageInfo;
|
|
677
|
+
const namespacedWorkspaceData = {};
|
|
678
|
+
Object.keys(allWorkspaceData).forEach(wsKey => {
|
|
679
|
+
try {
|
|
680
|
+
if (WorkspaceEntityNamespaceFunctionLookup[wsKey]) {
|
|
681
|
+
PackagesLogger.info(`JEST TEST: Preparing workspace data for import: ${wsKey}`);
|
|
682
|
+
namespacedWorkspaceData[wsKey] = WorkspaceEntityNamespaceFunctionLookup[wsKey].add(id, version, allWorkspaceData[wsKey]);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
catch (error) {
|
|
686
|
+
const message = `JEST TEST: error when preparing workspace data for import: ${wsKey}`;
|
|
687
|
+
if (error instanceof Error) {
|
|
688
|
+
PackagesLogger.error(message, error.message, error.name, error.stack, error);
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
PackagesLogger.error(message, error);
|
|
692
|
+
}
|
|
693
|
+
throw error;
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
return namespacedWorkspaceData;
|
|
697
|
+
};
|
|
698
|
+
exports.NamespaceWorkspaceData_Testing = NamespaceWorkspaceData_Testing;
|
|
699
|
+
// will remove namespaced package workspace data from allWorkspaceData and return the updated object
|
|
700
|
+
const RemoveNamespacedWorkspaceData_Testing = (allWorkspaceData, packageInfo) => {
|
|
701
|
+
const prunedWorkspaceData = {};
|
|
702
|
+
const { id } = packageInfo;
|
|
703
|
+
Object.keys(allWorkspaceData).forEach(wsKey => {
|
|
704
|
+
try {
|
|
705
|
+
if (WorkspaceEntityNamespaceFunctionLookup[wsKey]) {
|
|
706
|
+
PackagesLogger.info(`JEST TEST: Pruning workspace data: ${wsKey}`);
|
|
707
|
+
prunedWorkspaceData[wsKey] = WorkspaceEntityNamespaceFunctionLookup[wsKey].remove(id, allWorkspaceData[wsKey]);
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
prunedWorkspaceData[wsKey] = allWorkspaceData[wsKey];
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
catch (error) {
|
|
714
|
+
const message = `JEST TEST: error when pruning workspace data for: ${wsKey}`;
|
|
715
|
+
if (error instanceof Error) {
|
|
716
|
+
PackagesLogger.error(message, error.message, error.name, error.stack, error);
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
PackagesLogger.error(message, error);
|
|
720
|
+
}
|
|
721
|
+
throw error;
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
return prunedWorkspaceData;
|
|
725
|
+
};
|
|
726
|
+
exports.RemoveNamespacedWorkspaceData_Testing = RemoveNamespacedWorkspaceData_Testing;
|
|
727
|
+
const GetPackageSupportedEntityTypes = () => {
|
|
728
|
+
return Object.keys(WorkspaceEntityNamespaceFunctionLookup);
|
|
729
|
+
};
|
|
730
|
+
exports.GetPackageSupportedEntityTypes = GetPackageSupportedEntityTypes;
|
|
731
|
+
//# sourceMappingURL=Package.js.map
|
package/bin/Plan.js
CHANGED
|
@@ -25,12 +25,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.CreatePlan = void 0;
|
|
26
26
|
const Shared = __importStar(require("@coalescesoftware/shared"));
|
|
27
27
|
const fs_1 = __importDefault(require("fs"));
|
|
28
|
-
const CreatePlan = (path, environmentID, token, message) => {
|
|
28
|
+
const CreatePlan = (path, environmentID, token, message, runtimeParameters) => {
|
|
29
29
|
const fsSettings = {
|
|
30
30
|
fs: fs_1.default,
|
|
31
31
|
dir: path,
|
|
32
32
|
};
|
|
33
|
-
return Shared.DeployOperations.CreatePlanCLI(environmentID, fsSettings, token, Shared.Templates.PlatformType.snowflake)
|
|
33
|
+
return Shared.DeployOperations.CreatePlanCLI(environmentID, fsSettings, token, Shared.Templates.PlatformType.snowflake, runtimeParameters)
|
|
34
34
|
.then(result => {
|
|
35
35
|
const { plan } = result;
|
|
36
36
|
plan.gitInfo = { commit: { message: message }, oid: "" };
|
package/bin/RunOutput.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.SaveRunOutputToFile = void 0;
|
|
23
|
+
const Shared = __importStar(require("@coalescesoftware/shared"));
|
|
24
|
+
const CLILogger = Shared.Logging.GetLogger(Shared.Logging.LoggingArea.CLI);
|
|
25
|
+
const cleanRunResult = (nodeID, runResult) => {
|
|
26
|
+
return {
|
|
27
|
+
nodeID,
|
|
28
|
+
queryResultSequence: runResult.queryResultSequence
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
const GetRunOutputForRunCounter = (firestore, teamID, runID) => {
|
|
32
|
+
let runData;
|
|
33
|
+
return Shared.Runs.getRun(firestore, teamID, runID).get()
|
|
34
|
+
.then((runDataResult /*query snapshot*/) => {
|
|
35
|
+
if (!runDataResult.docs.length) {
|
|
36
|
+
const errorMessage = `wasnt able to get exactly one run for runID ${runID}`;
|
|
37
|
+
CLILogger.emergContext({
|
|
38
|
+
orgID: teamID
|
|
39
|
+
}, errorMessage);
|
|
40
|
+
throw new Error(errorMessage);
|
|
41
|
+
}
|
|
42
|
+
const runInfo = runDataResult.docs[0].data();
|
|
43
|
+
runData = {
|
|
44
|
+
runResults: {
|
|
45
|
+
runStartTime: runInfo.runStartTime,
|
|
46
|
+
runEndTime: runInfo.runEndTime,
|
|
47
|
+
runType: runInfo.runType,
|
|
48
|
+
runStatus: runInfo.runStatus,
|
|
49
|
+
runID: runInfo.id,
|
|
50
|
+
runResults: []
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return Shared.Runs.getRunRunResultsCollection(firestore, teamID, runID.toString())
|
|
54
|
+
.get().then((queryResult /*querySnapshot*/) => {
|
|
55
|
+
let runResults = {};
|
|
56
|
+
queryResult.docs.forEach((runResultDoc) => {
|
|
57
|
+
const stepCounter = runResultDoc.id;
|
|
58
|
+
const runResult = runResultDoc.data();
|
|
59
|
+
runResults[stepCounter] = cleanRunResult(stepCounter, runResult.history[0]);
|
|
60
|
+
});
|
|
61
|
+
runData.runResults.runResults = runInfo.runHistory.map((stepCounter) => {
|
|
62
|
+
return runResults[stepCounter];
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}).then(() => {
|
|
66
|
+
return runData;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const SaveRunOutputToFile = (runOutputFileLocation, runIDString, token) => {
|
|
70
|
+
return Shared.SchedulerOperations.AuthenticateFirebaseTokenAndRetrieveTeamInfoForCLI(token, undefined).then((authInfo) => {
|
|
71
|
+
const { teamInfo, firebase } = authInfo;
|
|
72
|
+
const teamID = teamInfo.fbTeamID;
|
|
73
|
+
const firestore = firebase.firestore();
|
|
74
|
+
const runID = parseInt(runIDString);
|
|
75
|
+
return GetRunOutputForRunCounter(firestore, teamID, runID);
|
|
76
|
+
}).then((runOutput) => {
|
|
77
|
+
const runOutputJSON = Shared.Common.StringifyFirestoreObject(runOutput);
|
|
78
|
+
return Shared.Common.WriteFile(runOutputFileLocation, runOutputJSON + "\n");
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
exports.SaveRunOutputToFile = SaveRunOutputToFile;
|
|
82
|
+
//# sourceMappingURL=RunOutput.js.map
|
package/bin/index.js
CHANGED
|
@@ -31,6 +31,7 @@ const Shared = __importStar(require("@coalescesoftware/shared"));
|
|
|
31
31
|
const CLIProfile = __importStar(require("./CLIProfile"));
|
|
32
32
|
const chalk_1 = __importDefault(require("chalk"));
|
|
33
33
|
const commander_1 = require("commander");
|
|
34
|
+
const CommonCLI = __importStar(require("./CommonCLI"));
|
|
34
35
|
const fs_1 = __importDefault(require("fs"));
|
|
35
36
|
// setting this needs to be first!
|
|
36
37
|
Shared.Logging.SetHTTPTransportOptions(Shared.Logging.EHttpServices.CLI);
|
|
@@ -39,7 +40,7 @@ const LogCLIInternal = Shared.Logging.GetLogger(Shared.Logging.LoggingArea.CLI_I
|
|
|
39
40
|
const program = new commander_1.Command();
|
|
40
41
|
program.version(require("../package.json").version, "-v, --version");
|
|
41
42
|
program.option("-b, --debug", "Output extra debugging", false);
|
|
42
|
-
program.option("--config <coa-config-location>", "coa config file location"
|
|
43
|
+
program.option("--config <coa-config-location>", "coa config file location");
|
|
43
44
|
const AddOverridesToCommand = (command) => {
|
|
44
45
|
Object.keys(CLIProfile.ICLIProfileExample).forEach((key) => {
|
|
45
46
|
command.option(`--${key} <value>`, CLIProfile.ICLIProfileExample[key], "");
|
|
@@ -93,10 +94,17 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Plan))
|
|
|
93
94
|
.then((configResult) => {
|
|
94
95
|
config = configResult;
|
|
95
96
|
return Shared.SchedulerOperations.AuthenticateFirebaseTokenAndRetrieveTeamInfoForCLI(config.token, undefined);
|
|
96
|
-
})
|
|
97
|
+
})
|
|
98
|
+
.then(({ teamInfo, firebase }) => {
|
|
99
|
+
const firestore = firebase.firestore();
|
|
97
100
|
Shared.Logging.SetBackendGlobalContext({ userID: teamInfo.fbUserID, orgID: teamInfo.fbTeamID });
|
|
101
|
+
const teamID = teamInfo.fbTeamID;
|
|
102
|
+
const environmentID = config.runDetails.environmentID;
|
|
103
|
+
return Shared.SchedulerOperations.GetRuntimeParametersObjectForRun(firestore, teamID, environmentID, config.runtimeParameters);
|
|
104
|
+
})
|
|
105
|
+
.then((runtimeParametersObject) => {
|
|
98
106
|
const envID = config.runDetails.environmentID;
|
|
99
|
-
return Plan.CreatePlan(directoryPath, envID, config.token, `Deploy to environment: ${envID}
|
|
107
|
+
return Plan.CreatePlan(directoryPath, envID, config.token, `Deploy to environment: ${envID}`, JSON.stringify(runtimeParametersObject));
|
|
100
108
|
}).then(result => {
|
|
101
109
|
const { plan, logContext } = result;
|
|
102
110
|
logContextToUse = logContext;
|
|
@@ -120,6 +128,7 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Plan))
|
|
|
120
128
|
*/
|
|
121
129
|
AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Deploy))
|
|
122
130
|
.option("-p, --plan <plan-location>", "Coalesce plan location", "./coa-plan.json")
|
|
131
|
+
.option("-o, --out <output json>", "Run Results Output in Json ")
|
|
123
132
|
.description("run a coalesce deployment plan")
|
|
124
133
|
.action((options, cmd) => {
|
|
125
134
|
const cliOverrides = ComputeCLIOverrides(cmd);
|
|
@@ -153,7 +162,7 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Deploy))
|
|
|
153
162
|
environmentID: config.runDetails.environmentID
|
|
154
163
|
},
|
|
155
164
|
userCredentials: config.userCredentials,
|
|
156
|
-
runTimeParameters: {}
|
|
165
|
+
runTimeParameters: plan.runtimeParameters || {},
|
|
157
166
|
};
|
|
158
167
|
Shared.Common.assert(Shared.Logging.LoggingArea.CLI, !!runInfo, "runinfo must exist to continue");
|
|
159
168
|
return Deploy.DeployWithCLI(plan, runInfo, config.token)
|
|
@@ -161,7 +170,10 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Deploy))
|
|
|
161
170
|
const { runCounter, runCompletion, logContext } = result;
|
|
162
171
|
logContextToUse = logContext !== null && logContext !== void 0 ? logContext : {};
|
|
163
172
|
LogCLI.infoContext(logContextToUse, chalk_1.default.whiteBright(`Job ${runCounter}: ${chalk_1.default.green("running")}...`));
|
|
164
|
-
return runCompletion
|
|
173
|
+
return runCompletion.finally(() => {
|
|
174
|
+
const outputFilePath = optsWithGlobals.out;
|
|
175
|
+
CommonCLI.FinishWithOutputFile(logContextToUse, outputFilePath, runCounter, config.token);
|
|
176
|
+
});
|
|
165
177
|
})
|
|
166
178
|
.then(() => {
|
|
167
179
|
LogCLI.infoContext(logContextToUse, "Deployment successful!");
|
|
@@ -178,6 +190,7 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Deploy))
|
|
|
178
190
|
*/
|
|
179
191
|
AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Refresh))
|
|
180
192
|
.description("runs a Coalesce pipeline")
|
|
193
|
+
.option("-o, --out <output json>", "Run Results Output in Json ")
|
|
181
194
|
.action((options, command) => {
|
|
182
195
|
const cliOverrides = ComputeCLIOverrides(command);
|
|
183
196
|
const optsWithGlobals = command.optsWithGlobals();
|
|
@@ -206,8 +219,14 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Refresh)
|
|
|
206
219
|
config = configResult;
|
|
207
220
|
return Shared.SchedulerOperations.AuthenticateFirebaseTokenAndRetrieveTeamInfoForCLI(config.token, undefined);
|
|
208
221
|
})
|
|
209
|
-
.then(({ teamInfo }) => {
|
|
222
|
+
.then(({ teamInfo, firebase }) => {
|
|
223
|
+
const firestore = firebase.firestore();
|
|
210
224
|
Shared.Logging.SetBackendGlobalContext({ userID: teamInfo.fbUserID, orgID: teamInfo.fbTeamID });
|
|
225
|
+
const teamID = teamInfo.fbTeamID;
|
|
226
|
+
const environmentID = config.runDetails.environmentID;
|
|
227
|
+
return Shared.SchedulerOperations.GetRuntimeParametersObjectForRun(firestore, teamID, environmentID, config.runtimeParameters);
|
|
228
|
+
})
|
|
229
|
+
.then((runtimeParametersObject) => {
|
|
211
230
|
runInfo = {
|
|
212
231
|
runType: Shared.Runner.ERunType.refresh,
|
|
213
232
|
runStatus: Shared.Runner.ERunStatus.running,
|
|
@@ -218,27 +237,30 @@ AddOverridesToCommand(program.command(Shared.CLIOperations.ECLICommands.Refresh)
|
|
|
218
237
|
excludeNodesSelector: config.runDetails.excludeNodesSelector
|
|
219
238
|
},
|
|
220
239
|
userCredentials: config.userCredentials,
|
|
221
|
-
runTimeParameters:
|
|
240
|
+
runTimeParameters: runtimeParametersObject,
|
|
222
241
|
};
|
|
242
|
+
Shared.Common.CleanupUndefinedValuesFromObject(runInfo);
|
|
223
243
|
LogCLIInternal.infoContext(logContextToUse, "cliOverrides", cliOverrides);
|
|
224
|
-
LogCLIInternal.infoContext(logContextToUse, "got the cli config", config)
|
|
225
|
-
LogCLIInternal.infoContext(logContextToUse, "got the run info", config)
|
|
244
|
+
//LogCLIInternal.infoContext(logContextToUse, "got the cli config", config)
|
|
245
|
+
//LogCLIInternal.infoContext(logContextToUse, "got the run info", config)
|
|
226
246
|
Shared.Common.assert(Shared.Logging.LoggingArea.CLI, !!runInfo, "runinfo must exist to continue");
|
|
227
247
|
return Refresh.RefreshWithCLI(config.token, runInfo)
|
|
228
248
|
.then((result) => {
|
|
229
249
|
const { runCounter, runCompletion, logContext } = result;
|
|
230
250
|
logContextToUse = logContext !== null && logContext !== void 0 ? logContext : {};
|
|
231
251
|
LogCLI.infoContext(logContextToUse, chalk_1.default.whiteBright(`Refresh run initialized. RunCounter: ${runCounter}`));
|
|
232
|
-
return runCompletion
|
|
252
|
+
return runCompletion.finally(() => {
|
|
253
|
+
const outputFilePath = optsWithGlobals.out;
|
|
254
|
+
CommonCLI.FinishWithOutputFile(logContextToUse, outputFilePath, runCounter, config.token);
|
|
255
|
+
}).then(() => {
|
|
256
|
+
LogCLI.infoContext(logContextToUse, "Refresh successful!");
|
|
257
|
+
Shared.CLIOperations.ExitCLISafe(0);
|
|
258
|
+
});
|
|
233
259
|
})
|
|
234
|
-
.
|
|
235
|
-
LogCLI.
|
|
236
|
-
Shared.CLIOperations.ExitCLISafe(
|
|
260
|
+
.catch(error => {
|
|
261
|
+
LogCLI.errorContext(logContextToUse, chalk_1.default.redBright(`Error during refresh!: ${error.toString()}`));
|
|
262
|
+
Shared.CLIOperations.ExitCLISafe(1);
|
|
237
263
|
});
|
|
238
|
-
})
|
|
239
|
-
.catch(error => {
|
|
240
|
-
LogCLI.errorContext(logContextToUse, chalk_1.default.redBright(`Error during refresh!: ${error.toString()}`));
|
|
241
|
-
Shared.CLIOperations.ExitCLISafe(1);
|
|
242
264
|
});
|
|
243
265
|
});
|
|
244
266
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coalescesoftware/coa",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.114",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"author": "Coalesce Automation, Inc.",
|
|
6
6
|
"main": "index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"start-cli-debug": "yarn run start --debug"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@coalescesoftware/shared": "^1.0.
|
|
15
|
+
"@coalescesoftware/shared": "^1.0.114",
|
|
16
16
|
"chalk": "^4.1.2",
|
|
17
17
|
"commander": "^9.2.0",
|
|
18
18
|
"firebase": "8.2.0",
|