@simplysf/simply-cicd-core 0.5.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/lib/build/createPackageVersion.js +20 -44
- package/lib/build/createPackageVersion.js.map +1 -1
- package/lib/build/createScratchOrg.d.ts +2 -1
- package/lib/build/createScratchOrg.js +38 -54
- package/lib/build/createScratchOrg.js.map +1 -1
- package/lib/build/deleteScratchOrg.js +2 -2
- package/lib/build/deleteScratchOrg.js.map +1 -1
- package/lib/build/devHubs.js +6 -6
- package/lib/build/devHubs.js.map +1 -1
- package/lib/build/pushScratch.js +40 -19
- package/lib/build/pushScratch.js.map +1 -1
- package/lib/deploy/deployProject.js +15 -14
- package/lib/deploy/deployProject.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/resolveOrg.d.ts +25 -0
- package/lib/resolveOrg.js +48 -0
- package/lib/resolveOrg.js.map +1 -0
- package/lib/sfApex.js +39 -34
- package/lib/sfApex.js.map +1 -1
- package/lib/sfAuth.d.ts +8 -1
- package/lib/sfAuth.js +65 -46
- package/lib/sfAuth.js.map +1 -1
- package/lib/sfDeploy.d.ts +34 -0
- package/lib/sfDeploy.js +78 -0
- package/lib/sfDeploy.js.map +1 -0
- package/lib/sfOrg.d.ts +38 -1
- package/lib/sfOrg.js +69 -8
- package/lib/sfOrg.js.map +1 -1
- package/lib/sfPackages.d.ts +27 -1
- package/lib/sfPackages.js +50 -5
- package/lib/sfPackages.js.map +1 -1
- package/lib/sfdxDependabot/dependabotRun.js +2 -2
- package/lib/sfdxDependabot/dependabotRun.js.map +1 -1
- package/package.json +6 -3
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export * from './logger.js';
|
|
|
32
32
|
export * from './sfApex.js';
|
|
33
33
|
export * from './sfAuth.js';
|
|
34
34
|
export * from './sfConfig.js';
|
|
35
|
+
export * from './sfDeploy.js';
|
|
35
36
|
export * from './sfOrg.js';
|
|
36
37
|
export * from './sfPackages.js';
|
|
37
38
|
export * from './sfPlugins.js';
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,mGAAmG;AACnG,iGAAiG;AACjG,qGAAqG;AACrG,qGAAqG;AACrG,wGAAwG;AACxG,6DAA6D;AAC7D,EAAE;AACF,gGAAgG;AAChG,iGAAiG;AACjG,uEAAuE;AAEvE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAE/B,gBAAgB;AAChB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAE/B,SAAS;AACT,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAE5C,UAAU;AACV,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAErC,QAAQ;AACR,cAAc,iBAAiB,CAAC;AAEhC,SAAS;AACT,cAAc,gBAAgB,CAAC;AAE/B,aAAa;AACb,cAAc,qCAAqC,CAAC;AAEpD,UAAU;AACV,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AAEtC,WAAW;AACX,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AAEzC,kBAAkB;AAClB,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,mGAAmG;AACnG,iGAAiG;AACjG,qGAAqG;AACrG,qGAAqG;AACrG,wGAAwG;AACxG,6DAA6D;AAC7D,EAAE;AACF,gGAAgG;AAChG,iGAAiG;AACjG,uEAAuE;AAEvE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAE/B,gBAAgB;AAChB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAE/B,SAAS;AACT,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AACnD,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC;AACnC,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAE5C,UAAU;AACV,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAErC,QAAQ;AACR,cAAc,iBAAiB,CAAC;AAEhC,SAAS;AACT,cAAc,gBAAgB,CAAC;AAE/B,aAAa;AACb,cAAc,qCAAqC,CAAC;AAEpD,UAAU;AACV,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AAEtC,WAAW;AACX,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AAEzC,kBAAkB;AAClB,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AuthInfo, Org } from '@salesforce/core';
|
|
2
|
+
export type ResolveOrgOptions = {
|
|
3
|
+
/** Fall back to the default Dev Hub (`target-dev-hub`) instead of the default target org. */
|
|
4
|
+
isDevHub?: boolean;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The authenticated org that an `--alias`/`--target-org`-style value names, resolved the way `sf`
|
|
8
|
+
* resolves `--target-org`: an alias or the username of an existing auth, with a blank value meaning
|
|
9
|
+
* the default target org (or, with `isDevHub`, the default Dev Hub).
|
|
10
|
+
*
|
|
11
|
+
* The default is re-read from disk on every call. `@salesforce/core` caches config per process, so
|
|
12
|
+
* without that a default set earlier in the same run (`setDefault` on a login or a scratch org
|
|
13
|
+
* create) would be missed, and the previous default org used instead.
|
|
14
|
+
*
|
|
15
|
+
* @throws {SfError} `NamedOrgNotFoundError` if no auth exists for the alias/username;
|
|
16
|
+
* `NoUsernameFoundError` if the value is blank and no default is set.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveOrg(aliasOrUsername?: string, options?: ResolveOrgOptions): Promise<Org>;
|
|
19
|
+
/**
|
|
20
|
+
* The saved auth for an alias or username, without connecting to the org. `AuthInfo.create` only
|
|
21
|
+
* accepts a username, so an alias is resolved to its username first.
|
|
22
|
+
*
|
|
23
|
+
* @throws {SfError} `NamedOrgNotFoundError` if no auth exists for the alias/username.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveAuthInfo(aliasOrUsername: string): Promise<AuthInfo>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, SimplySF.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { AuthInfo, ConfigAggregator, Org, StateAggregator } from '@salesforce/core';
|
|
17
|
+
/**
|
|
18
|
+
* The authenticated org that an `--alias`/`--target-org`-style value names, resolved the way `sf`
|
|
19
|
+
* resolves `--target-org`: an alias or the username of an existing auth, with a blank value meaning
|
|
20
|
+
* the default target org (or, with `isDevHub`, the default Dev Hub).
|
|
21
|
+
*
|
|
22
|
+
* The default is re-read from disk on every call. `@salesforce/core` caches config per process, so
|
|
23
|
+
* without that a default set earlier in the same run (`setDefault` on a login or a scratch org
|
|
24
|
+
* create) would be missed, and the previous default org used instead.
|
|
25
|
+
*
|
|
26
|
+
* @throws {SfError} `NamedOrgNotFoundError` if no auth exists for the alias/username;
|
|
27
|
+
* `NoUsernameFoundError` if the value is blank and no default is set.
|
|
28
|
+
*/
|
|
29
|
+
export async function resolveOrg(aliasOrUsername, options = {}) {
|
|
30
|
+
const { isDevHub } = options;
|
|
31
|
+
const name = aliasOrUsername?.trim();
|
|
32
|
+
if (name) {
|
|
33
|
+
return Org.create({ aliasOrUsername: name, isDevHub });
|
|
34
|
+
}
|
|
35
|
+
const aggregator = await (await ConfigAggregator.create()).reload();
|
|
36
|
+
return Org.create({ aggregator, isDevHub });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The saved auth for an alias or username, without connecting to the org. `AuthInfo.create` only
|
|
40
|
+
* accepts a username, so an alias is resolved to its username first.
|
|
41
|
+
*
|
|
42
|
+
* @throws {SfError} `NamedOrgNotFoundError` if no auth exists for the alias/username.
|
|
43
|
+
*/
|
|
44
|
+
export async function resolveAuthInfo(aliasOrUsername) {
|
|
45
|
+
const stateAggregator = await StateAggregator.getInstance();
|
|
46
|
+
return AuthInfo.create({ username: stateAggregator.aliases.resolveUsername(aliasOrUsername.trim()) });
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=resolveOrg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveOrg.js","sourceRoot":"","sources":["../src/resolveOrg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOpF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,eAAwB,EAAE,UAA6B,EAAE;IACxF,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,IAAI,GAAG,eAAe,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACpE,OAAO,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,eAAuB;IAC3D,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,CAAC;IAC5D,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AACxG,CAAC"}
|
package/lib/sfApex.js
CHANGED
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { promises as fs } from 'node:fs';
|
|
17
17
|
import path from 'node:path';
|
|
18
|
-
import {
|
|
18
|
+
import { Duration } from '@salesforce/kit';
|
|
19
|
+
import { runApexTestsWithResults } from '@simplysf/simply-apex-core';
|
|
19
20
|
import { readSfdxProject } from '@simplysf/simply-core';
|
|
20
|
-
import { runSf } from './exec/sfCli.js';
|
|
21
21
|
import { logger } from './logger.js';
|
|
22
|
+
import { getOrgConnection } from './sfOrg.js';
|
|
22
23
|
/**
|
|
23
24
|
* Checks if there are any Apex test classes defined in the package directories, by reading
|
|
24
25
|
* `sfdx-project.json` to identify the package directories and searching each recursively
|
|
@@ -38,24 +39,40 @@ export async function hasApexTests(options) {
|
|
|
38
39
|
for (const dir of packageDirs) {
|
|
39
40
|
try {
|
|
40
41
|
// eslint-disable-next-line no-await-in-loop -- stops at the first directory with a match
|
|
41
|
-
await
|
|
42
|
-
|
|
42
|
+
if (await directoryHasApexTests(dir)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (options?.debugMode) {
|
|
46
|
+
logger.log(`No Apex tests found in ${dir}.`);
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
catch (error) {
|
|
45
50
|
if (options?.debugMode) {
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
logger.log(`No Apex tests found in ${dir} or an error occurred during search.`, error.message);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/** What `grep -q -r -i --include=*.cls '@isTest\b' <dir>` checked, without depending on grep. */
|
|
58
|
+
async function directoryHasApexTests(dir) {
|
|
59
|
+
const entries = await fs.readdir(dir, { recursive: true, withFileTypes: true });
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
if (entry.isFile() && entry.name.endsWith('.cls')) {
|
|
62
|
+
// eslint-disable-next-line no-await-in-loop -- stops at the first match
|
|
63
|
+
const source = await fs.readFile(path.join(entry.parentPath, entry.name), 'utf-8');
|
|
64
|
+
if (/@isTest\b/i.test(source)) {
|
|
65
|
+
return true;
|
|
48
66
|
}
|
|
49
67
|
}
|
|
50
68
|
}
|
|
51
69
|
return false;
|
|
52
70
|
}
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
55
|
-
|
|
56
|
-
async function executeTestRun(args) {
|
|
71
|
+
/** Runs the tests, swallowing any failure so the run's artifacts (namely the test run ID file) can
|
|
72
|
+
* still be inspected afterward to distinguish an execution failure from a genuine test failure. */
|
|
73
|
+
async function executeTestRun(alias, options) {
|
|
57
74
|
try {
|
|
58
|
-
await
|
|
75
|
+
await runApexTestsWithResults({ ...options, connection: await getOrgConnection(alias) });
|
|
59
76
|
return undefined;
|
|
60
77
|
}
|
|
61
78
|
catch (e) {
|
|
@@ -70,7 +87,7 @@ async function resolveTestRunId(testRunIdFile, execError) {
|
|
|
70
87
|
}
|
|
71
88
|
catch (readIdError) {
|
|
72
89
|
if (execError) {
|
|
73
|
-
logger.error('Apex test run failed.', execError.
|
|
90
|
+
logger.error('Apex test run failed.', execError.message);
|
|
74
91
|
throw execError;
|
|
75
92
|
}
|
|
76
93
|
logger.error(`Failed to read test run ID from ${testRunIdFile}.`, readIdError.message);
|
|
@@ -134,28 +151,16 @@ export async function runApexTests(options) {
|
|
|
134
151
|
logger.info('Running Apex tests...');
|
|
135
152
|
const testResultsDir = './test-results/apex';
|
|
136
153
|
await fs.mkdir(testResultsDir, { recursive: true });
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
wait,
|
|
148
|
-
];
|
|
149
|
-
if (alias) {
|
|
150
|
-
args.push('--target-org', alias);
|
|
151
|
-
}
|
|
152
|
-
if (testSuite) {
|
|
153
|
-
args.push('--suite-names', testSuite);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
args.push('--test-level', testLevel);
|
|
157
|
-
}
|
|
158
|
-
const execError = await executeTestRun(args);
|
|
154
|
+
// What `sf apex test run --code-coverage --result-format junit --output-dir <dir> --wait <wait>
|
|
155
|
+
// [--suite-names <suite> | --test-level <level>]` ran and wrote.
|
|
156
|
+
const execError = await executeTestRun(alias, {
|
|
157
|
+
codeCoverage: true,
|
|
158
|
+
outputDir: testResultsDir,
|
|
159
|
+
wait: Duration.minutes(Number(wait)),
|
|
160
|
+
...(testSuite
|
|
161
|
+
? { suiteNames: [testSuite] }
|
|
162
|
+
: { testLevel: testLevel }),
|
|
163
|
+
});
|
|
159
164
|
const testRunId = await resolveTestRunId(path.join(testResultsDir, 'test-run-id.txt'), execError);
|
|
160
165
|
let testRunOutcome;
|
|
161
166
|
if (testRunId) {
|
package/lib/sfApex.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sfApex.js","sourceRoot":"","sources":["../src/sfApex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sfApex.js","sourceRoot":"","sources":["../src/sfApex.ts"],"names":[],"mappings":"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"}
|
package/lib/sfAuth.d.ts
CHANGED
|
@@ -12,8 +12,15 @@ export type AuthenticateOrgOptions = {
|
|
|
12
12
|
export type AuthenticateOrgResult = {
|
|
13
13
|
success: boolean;
|
|
14
14
|
username?: string;
|
|
15
|
+
/** The saved auth fields, as `sf org login … --json` returned them (tokens decrypted). */
|
|
15
16
|
result?: unknown;
|
|
16
17
|
message?: string;
|
|
17
18
|
};
|
|
18
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Authenticates to a Salesforce org using either a JWT flow or an SFDX auth URL, in-process via
|
|
21
|
+
* `@salesforce/core`. The auth, alias and default-org settings are written to the same `~/.sf`
|
|
22
|
+
* state `sf org login jwt` / `sf org login sfdx-url` write, so later `sf` processes see them.
|
|
23
|
+
*
|
|
24
|
+
* @throws If authentication fails; the failure is logged first.
|
|
25
|
+
*/
|
|
19
26
|
export declare function authenticateOrg(options: AuthenticateOrgOptions): Promise<AuthenticateOrgResult>;
|
package/lib/sfAuth.js
CHANGED
|
@@ -13,61 +13,80 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import { tmpdir } from 'node:os';
|
|
18
|
-
import { join } from 'node:path';
|
|
19
|
-
import { runSf } from './exec/sfCli.js';
|
|
16
|
+
import { AuthInfo, AuthRemover, SfdcUrl, SfError, SfProject } from '@salesforce/core';
|
|
20
17
|
import { logger } from './logger.js';
|
|
21
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Where a JWT login goes: the given instance URL, else the project's `sfdcLoginUrl`, else
|
|
20
|
+
* production — the same resolution `sf org login jwt` applies, including its refusal of a
|
|
21
|
+
* Lightning domain (`*.lightning.force.com`), which can't serve OAuth.
|
|
22
|
+
*/
|
|
23
|
+
async function resolveLoginUrl(instanceUrl) {
|
|
24
|
+
let loginUrl = instanceUrl;
|
|
25
|
+
if (!loginUrl) {
|
|
26
|
+
try {
|
|
27
|
+
const projectJson = await (await SfProject.resolve()).resolveProjectConfig();
|
|
28
|
+
loginUrl = typeof projectJson.sfdcLoginUrl === 'string' ? projectJson.sfdcLoginUrl : SfdcUrl.PRODUCTION;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
loginUrl = SfdcUrl.PRODUCTION;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const url = new SfdcUrl(loginUrl);
|
|
35
|
+
if (url.isLightningDomain() || (url.isInternalUrl() && url.origin.includes('.lightning.'))) {
|
|
36
|
+
throw new SfError('Use the "My Domain" URL (.my.salesforce.com) as the instance URL, not the Lightning domain (.lightning.force.com).', 'LightningDomain');
|
|
37
|
+
}
|
|
38
|
+
return loginUrl;
|
|
39
|
+
}
|
|
40
|
+
/** JWT bearer login, as `sf org login jwt`: an existing auth file for the user is replaced. */
|
|
41
|
+
async function loginWithJwt(username, oauth2Options) {
|
|
42
|
+
try {
|
|
43
|
+
return await AuthInfo.create({ username, oauth2Options });
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error.name !== 'AuthInfoOverwriteError') {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
await (await AuthRemover.create()).removeAuth(username);
|
|
50
|
+
return AuthInfo.create({ username, oauth2Options });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Authenticates to a Salesforce org using either a JWT flow or an SFDX auth URL, in-process via
|
|
55
|
+
* `@salesforce/core`. The auth, alias and default-org settings are written to the same `~/.sf`
|
|
56
|
+
* state `sf org login jwt` / `sf org login sfdx-url` write, so later `sf` processes see them.
|
|
57
|
+
*
|
|
58
|
+
* @throws If authentication fails; the failure is logged first.
|
|
59
|
+
*/
|
|
22
60
|
export async function authenticateOrg(options) {
|
|
23
61
|
const { alias, authUrl, clientId, instanceUrl, jwtKeyFile, username, setDefault, setDefaultDevHub, debug } = options;
|
|
24
62
|
const authEntity = alias ?? username ?? 'unknown org';
|
|
25
63
|
logger.info(`Authenticating to org: ${authEntity}`);
|
|
26
64
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
jwtKeyFile ?? '',
|
|
43
|
-
'--client-id',
|
|
44
|
-
clientId ?? '',
|
|
45
|
-
'--instance-url',
|
|
46
|
-
instanceUrl ?? '',
|
|
47
|
-
'--json',
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
|
-
if (alias) {
|
|
51
|
-
authArgs.push('--alias', alias);
|
|
52
|
-
}
|
|
53
|
-
if (setDefault) {
|
|
54
|
-
authArgs.push('--set-default');
|
|
55
|
-
}
|
|
56
|
-
if (setDefaultDevHub) {
|
|
57
|
-
authArgs.push('--set-default-dev-hub');
|
|
58
|
-
}
|
|
59
|
-
const { stdout } = await runSf(authArgs);
|
|
65
|
+
const authInfo = authUrl
|
|
66
|
+
? await AuthInfo.create({ oauth2Options: AuthInfo.parseSfdxAuthUrl(authUrl) })
|
|
67
|
+
: await loginWithJwt(username ?? '', {
|
|
68
|
+
clientId,
|
|
69
|
+
privateKeyFile: jwtKeyFile,
|
|
70
|
+
loginUrl: await resolveLoginUrl(instanceUrl),
|
|
71
|
+
});
|
|
72
|
+
await authInfo.save();
|
|
73
|
+
await authInfo.handleAliasAndDefaultSettings({
|
|
74
|
+
alias,
|
|
75
|
+
setDefault: setDefault ?? false,
|
|
76
|
+
setDefaultDevHub: setDefaultDevHub ?? false,
|
|
77
|
+
});
|
|
78
|
+
const fields = authUrl ? { clientSecret: '', ...authInfo.getFields(true) } : authInfo.getFields(true);
|
|
79
|
+
await AuthInfo.identifyPossibleScratchOrgs(fields, authInfo);
|
|
60
80
|
if (debug) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return { success: false, message: authResult.message, username };
|
|
81
|
+
// Only identifying fields: the CLI's --json output this used to print included live tokens.
|
|
82
|
+
logger.debug('Authenticated:', {
|
|
83
|
+
username: fields.username,
|
|
84
|
+
orgId: fields.orgId,
|
|
85
|
+
instanceUrl: fields.instanceUrl,
|
|
86
|
+
});
|
|
68
87
|
}
|
|
69
88
|
logger.success(`Successfully authenticated to org: ${authEntity}`);
|
|
70
|
-
return { success: true, username, result:
|
|
89
|
+
return { success: true, username: fields.username ?? username, result: fields };
|
|
71
90
|
}
|
|
72
91
|
catch (error) {
|
|
73
92
|
logger.error(`Authentication failed for ${authEntity}`);
|
package/lib/sfAuth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sfAuth.js","sourceRoot":"","sources":["../src/sfAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"sfAuth.js","sourceRoot":"","sources":["../src/sfAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Duration } from '@salesforce/kit';
|
|
2
|
+
import { RequestStatus } from '@salesforce/source-deploy-retrieve';
|
|
3
|
+
export type DeployProjectSourceOptions = {
|
|
4
|
+
/** The org to deploy to. Omit to use the default target org. */
|
|
5
|
+
aliasOrUsername?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Deploy these directories instead of the tracked local changes (`--source-dir`). Source tracking
|
|
8
|
+
* still records what was deployed.
|
|
9
|
+
*/
|
|
10
|
+
sourceDirs?: string[];
|
|
11
|
+
/** `--ignore-warnings`: don't fail the deploy on warnings. */
|
|
12
|
+
ignoreWarnings?: boolean;
|
|
13
|
+
/** How long to wait for the deploy to finish. */
|
|
14
|
+
wait: Duration;
|
|
15
|
+
};
|
|
16
|
+
export type DeployProjectSourceResult = {
|
|
17
|
+
/** `undefined` when there were no local changes to deploy. */
|
|
18
|
+
deployId?: string;
|
|
19
|
+
status: RequestStatus | 'NothingToDeploy';
|
|
20
|
+
componentCount: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Deploys project source to an org with source tracking, as
|
|
24
|
+
* `sf project deploy start --ignore-conflicts [--source-dir …] [--ignore-warnings] --wait <wait>` does:
|
|
25
|
+
* without `sourceDirs`, it deploys the tracked local changes (deletes included), and nothing to
|
|
26
|
+
* deploy is not an error; with `sourceDirs`, it deploys those, and an empty set is.
|
|
27
|
+
*
|
|
28
|
+
* Remote conflicts are ignored and tracking is updated after the deploy, as `--ignore-conflicts`
|
|
29
|
+
* does. Anything short of a full success (partial success, failure, cancellation, or still running
|
|
30
|
+
* at `wait`) throws, as the CLI exits non-zero for each of them.
|
|
31
|
+
*
|
|
32
|
+
* @throws {SfError} `NothingToDeploy` for empty `sourceDirs`; `DeployFailed` for any non-success.
|
|
33
|
+
*/
|
|
34
|
+
export declare function deployProjectSource(options: DeployProjectSourceOptions): Promise<DeployProjectSourceResult>;
|
package/lib/sfDeploy.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, SimplySF.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { SfError, SfProject } from '@salesforce/core';
|
|
17
|
+
import { ComponentSet, ComponentSetBuilder, ComponentStatus, RequestStatus } from '@salesforce/source-deploy-retrieve';
|
|
18
|
+
import { SourceTracking } from '@salesforce/source-tracking';
|
|
19
|
+
import { logger } from './logger.js';
|
|
20
|
+
import { resolveOrg } from './resolveOrg.js';
|
|
21
|
+
/**
|
|
22
|
+
* Deploys project source to an org with source tracking, as
|
|
23
|
+
* `sf project deploy start --ignore-conflicts [--source-dir …] [--ignore-warnings] --wait <wait>` does:
|
|
24
|
+
* without `sourceDirs`, it deploys the tracked local changes (deletes included), and nothing to
|
|
25
|
+
* deploy is not an error; with `sourceDirs`, it deploys those, and an empty set is.
|
|
26
|
+
*
|
|
27
|
+
* Remote conflicts are ignored and tracking is updated after the deploy, as `--ignore-conflicts`
|
|
28
|
+
* does. Anything short of a full success (partial success, failure, cancellation, or still running
|
|
29
|
+
* at `wait`) throws, as the CLI exits non-zero for each of them.
|
|
30
|
+
*
|
|
31
|
+
* @throws {SfError} `NothingToDeploy` for empty `sourceDirs`; `DeployFailed` for any non-success.
|
|
32
|
+
*/
|
|
33
|
+
export async function deployProjectSource(options) {
|
|
34
|
+
const { aliasOrUsername, sourceDirs, ignoreWarnings = false, wait } = options;
|
|
35
|
+
const org = await resolveOrg(aliasOrUsername);
|
|
36
|
+
const project = await SfProject.resolve();
|
|
37
|
+
const tracking = await SourceTracking.create({ org, project, subscribeSDREvents: true, ignoreConflicts: true });
|
|
38
|
+
const componentSet = sourceDirs?.length
|
|
39
|
+
? await ComponentSetBuilder.build({
|
|
40
|
+
sourcepath: sourceDirs,
|
|
41
|
+
sourceapiversion: project.getSfProjectJson().getContents().sourceApiVersion,
|
|
42
|
+
projectDir: tracking.projectPath,
|
|
43
|
+
})
|
|
44
|
+
: ((await tracking.localChangesAsComponentSet(false))[0] ?? new ComponentSet(undefined, tracking.registry));
|
|
45
|
+
if (componentSet.size === 0) {
|
|
46
|
+
if (sourceDirs?.length) {
|
|
47
|
+
throw new SfError(`No local changes to deploy in ${sourceDirs.join(', ')}.`, 'NothingToDeploy');
|
|
48
|
+
}
|
|
49
|
+
logger.info('No local changes to deploy.');
|
|
50
|
+
return { status: 'NothingToDeploy', componentCount: 0 };
|
|
51
|
+
}
|
|
52
|
+
logger.info(`Deploying ${componentSet.size} components...`);
|
|
53
|
+
const deploy = await componentSet.deploy({
|
|
54
|
+
usernameOrConnection: org.getConnection(),
|
|
55
|
+
apiOptions: { checkOnly: false, ignoreWarnings, rest: false, rollbackOnError: true, purgeOnDelete: false },
|
|
56
|
+
});
|
|
57
|
+
let lastProgress = '';
|
|
58
|
+
deploy.onUpdate((response) => {
|
|
59
|
+
const progress = `Deploy ${response.id}: ${response.status} (${response.numberComponentsDeployed}/${response.numberComponentsTotal} components, ${response.numberTestsCompleted}/${response.numberTestsTotal} tests)`;
|
|
60
|
+
if (progress !== lastProgress) {
|
|
61
|
+
lastProgress = progress;
|
|
62
|
+
logger.info(progress);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const result = await deploy.pollStatus({ timeout: wait });
|
|
66
|
+
const { status } = result.response;
|
|
67
|
+
if (status !== RequestStatus.Succeeded) {
|
|
68
|
+
const failures = result.getFileResponses().filter((file) => file.state === ComponentStatus.Failed);
|
|
69
|
+
for (const failure of failures) {
|
|
70
|
+
const reason = 'error' in failure ? failure.error : '';
|
|
71
|
+
logger.error(`${failure.type} ${failure.fullName}: ${reason}`);
|
|
72
|
+
}
|
|
73
|
+
const errorMessage = result.response.errorMessage ? ` ${result.response.errorMessage}` : '';
|
|
74
|
+
throw new SfError(`Deploy ${deploy.id ?? ''} finished with status ${status} (${failures.length} component failures).${errorMessage}`, 'DeployFailed');
|
|
75
|
+
}
|
|
76
|
+
return { deployId: deploy.id, status, componentCount: componentSet.size };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=sfDeploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfDeploy.js","sourceRoot":"","sources":["../src/sfDeploy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACvH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuB7C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAmC;IAC3E,MAAM,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAC9E,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhH,MAAM,YAAY,GAAG,UAAU,EAAE,MAAM;QACrC,CAAC,CAAC,MAAM,mBAAmB,CAAC,KAAK,CAAC;YAC9B,UAAU,EAAE,UAAU;YACtB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,WAAW,EAAE,CAAC,gBAAgB;YAC3E,UAAU,EAAE,QAAQ,CAAC,WAAW;SACjC,CAAC;QACJ,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE9G,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,UAAU,EAAE,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,OAAO,CAAC,iCAAiC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAClG,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,aAAa,YAAY,CAAC,IAAI,gBAAgB,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC;QACvC,oBAAoB,EAAE,GAAG,CAAC,aAAa,EAAE;QACzC,UAAU,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC3G,CAAC,CAAC;IACH,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,UAAU,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,wBAAwB,IAAI,QAAQ,CAAC,qBAAqB,gBAAgB,QAAQ,CAAC,oBAAoB,IAAI,QAAQ,CAAC,gBAAgB,SAAS,CAAC;QACtN,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC9B,YAAY,GAAG,QAAQ,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IACnC,IAAI,MAAM,KAAK,aAAa,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,eAAe,CAAC,MAAM,CAAC,CAAC;QACnG,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,OAAO,CACf,UAAU,MAAM,CAAC,EAAE,IAAI,EAAE,yBAAyB,MAAM,KAAK,QAAQ,CAAC,MAAM,wBAAwB,YAAY,EAAE,EAClH,cAAc,CACf,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC;AAC5E,CAAC"}
|
package/lib/sfOrg.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { type Connection } from '@salesforce/core';
|
|
|
2
2
|
/**
|
|
3
3
|
* The org's instance URL, e.g. `https://my-domain.my.salesforce.com`.
|
|
4
4
|
*
|
|
5
|
-
* @param aliasOrUsername - The org to look up
|
|
5
|
+
* @param aliasOrUsername - The org to look up: an alias or username of an existing auth. Omit (or
|
|
6
|
+
* pass `''`) to use the default target org.
|
|
6
7
|
*/
|
|
7
8
|
export declare function getOrgInstanceUrl(aliasOrUsername?: string): Promise<string>;
|
|
8
9
|
/**
|
|
@@ -48,3 +49,39 @@ export declare function assignPermissionSets(permissionSetNames: string[], alias
|
|
|
48
49
|
* @throws {AssignmentError} If any assignment failed; the others are still attempted.
|
|
49
50
|
*/
|
|
50
51
|
export declare function assignPermissionSetLicenses(licenseNames: string[], aliasOrUsername?: string): Promise<void>;
|
|
52
|
+
/** What `sf org create scratch --json` returns: the fields `SCRATCH_ORG_INFO.json` is written from. */
|
|
53
|
+
export type CreatedScratchOrg = {
|
|
54
|
+
username?: string;
|
|
55
|
+
scratchOrgInfo?: Record<string, unknown>;
|
|
56
|
+
authFields?: Record<string, unknown>;
|
|
57
|
+
warnings: string[];
|
|
58
|
+
orgId?: string;
|
|
59
|
+
};
|
|
60
|
+
export type CreateScratchOrgOnHubOptions = {
|
|
61
|
+
/** Path to the scratch org definition file. */
|
|
62
|
+
definitionFile: string;
|
|
63
|
+
durationDays: number;
|
|
64
|
+
/** Minutes to wait for the org to be ready. */
|
|
65
|
+
waitMinutes: number;
|
|
66
|
+
/** Make the new org the default target org (`--set-default`). */
|
|
67
|
+
setDefault?: boolean;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Creates a scratch org from a Dev Hub, as `sf org create scratch --definition-file … --json` does,
|
|
71
|
+
* and returns the same result shape. The org is authenticated and source tracking is enabled, as
|
|
72
|
+
* the CLI's defaults.
|
|
73
|
+
*
|
|
74
|
+
* @param hubAliasOrUsername - The Dev Hub. Must already be authenticated.
|
|
75
|
+
* @throws {SfError} If signup fails or doesn't finish within the wait.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createScratchOrgOnHub(hubAliasOrUsername: string, options: CreateScratchOrgOnHubOptions): Promise<CreatedScratchOrg>;
|
|
78
|
+
/**
|
|
79
|
+
* Deletes a scratch org, as `sf org delete scratch --no-prompt` does: refuses a non-scratch org,
|
|
80
|
+
* treats an already-deleted org as success, and removes the local auth for one whose domain no
|
|
81
|
+
* longer resolves.
|
|
82
|
+
*
|
|
83
|
+
* @param aliasOrUsername - The scratch org. Omit to use the default target org.
|
|
84
|
+
* @returns The deleted org's username.
|
|
85
|
+
* @throws {SfError} If the org isn't a scratch org, or the Dev Hub rejects the delete.
|
|
86
|
+
*/
|
|
87
|
+
export declare function deleteTargetScratchOrg(aliasOrUsername?: string): Promise<string>;
|