@uipath/solution-tool 1.202.0 → 1.203.0-preview.160
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/dist/THIRD-PARTY-NOTICES.md +23 -1
- package/dist/deploy.js +7 -6
- package/dist/{packager-tool-bt0z25tw.js → embedded-file-reader-xxqe8vs8.js} +98 -16584
- package/dist/first-party-service-sd8yaf73.js +27 -0
- package/dist/index-dqa169gp.js +25 -0
- package/dist/index.js +19 -13
- package/dist/init.js +8 -5
- package/dist/{list-8hvfmge6.js → list-dadxggxt.js} +5 -4
- package/dist/models/pack-command-types.d.ts +33 -5
- package/dist/pack.js +12 -6
- package/dist/{packager-tool-fjjh5veg.js → packager-tool-0f0wt9vh.js} +353 -1519
- package/dist/{packager-tool-pbmpgz04.js → packager-tool-1haahq17.js} +5 -3
- package/dist/{packager-tool-rbrcxjch.js → packager-tool-2syrt51a.js} +7 -4
- package/dist/packager-tool-3jrq7smt.js +1459 -0
- package/dist/packager-tool-53w8skv5.js +262 -0
- package/dist/packager-tool-7znqtw3f.js +244 -0
- package/dist/packager-tool-bkwnetqn.js +16678 -0
- package/dist/{packager-tool-5518wy6n.js → packager-tool-cp07fhx3.js} +9 -6
- package/dist/{packager-tool-w1dzcj31.js → packager-tool-cvfbzs9p.js} +359 -95
- package/dist/packager-tool-gdtpsdn7.js +342 -0
- package/dist/{packager-tool-pyygbnp2.js → packager-tool-htag6yh5.js} +4 -4
- package/dist/{packager-tool-3bewrpq4.js → packager-tool-jz2wbfjz.js} +4 -1
- package/dist/packager-tool-k4mskzww.js +125 -0
- package/dist/{packager-tool-vfcht7hq.js → packager-tool-mj5p341c.js} +11 -12
- package/dist/{packager-tool-bme8epz8.js → packager-tool-n4nfqj99.js} +15381 -2421
- package/dist/{packager-tool-mcpzmn0v.js → packager-tool-rc5pcf2n.js} +45 -21
- package/dist/packager-tool-resolver-fmjr60x8.js +19 -0
- package/dist/{packager-tool-pw7v82j2.js → packager-tool-vas0xg5h.js} +1 -1
- package/dist/packager-tool-znakt6yw.js +188 -0
- package/dist/packager-tool.d.ts +1 -1
- package/dist/packager-tool.js +1 -1
- package/dist/prepare-solution-resources-wds3r8bq.js +22 -0
- package/dist/project-contributions-cvttys34.js +27 -0
- package/dist/publish.js +7 -6
- package/dist/resource.js +7 -4
- package/dist/services/deployment-validation.d.ts +33 -0
- package/dist/services/governance-options.d.ts +61 -1
- package/dist/services/pack-command-service.d.ts +33 -2
- package/dist/services/packager-tool-resolver.d.ts +3 -0
- package/dist/services/prepare-solution-resources.d.ts +40 -0
- package/dist/services/project-contributions.d.ts +58 -0
- package/dist/services/project-type-tools.d.ts +6 -0
- package/dist/templates/AGENTS.md +78 -8
- package/dist/tool.js +19 -13
- package/package.json +3 -2
- package/dist/services/validate-appv2-action-schemas.d.ts +0 -10
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getStudioWebAuthWithOrganizationId,
|
|
3
3
|
useStudioWebAuth
|
|
4
|
-
} from "./packager-tool-
|
|
4
|
+
} from "./packager-tool-1haahq17.js";
|
|
5
5
|
import {
|
|
6
6
|
activateDeploymentAsync,
|
|
7
7
|
deployRunAsync,
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
listPackagesAsync,
|
|
12
12
|
uninstallDeploymentAsync,
|
|
13
13
|
upgradeDeploymentAsync
|
|
14
|
-
} from "./packager-tool-
|
|
14
|
+
} from "./packager-tool-rc5pcf2n.js";
|
|
15
15
|
import {
|
|
16
16
|
SolutionInitError,
|
|
17
17
|
solutionInitAsync
|
|
18
|
-
} from "./packager-tool-
|
|
18
|
+
} from "./packager-tool-vas0xg5h.js";
|
|
19
19
|
import {
|
|
20
20
|
GOVERNANCE_OPTION_INSTRUCTIONS,
|
|
21
21
|
PackCommandService,
|
|
@@ -24,16 +24,22 @@ import {
|
|
|
24
24
|
applyAuthConnection,
|
|
25
25
|
checkSolutionPathAsync,
|
|
26
26
|
createSolutionPackager,
|
|
27
|
-
ensurePackagerTools,
|
|
28
|
-
isUnpackableProjectTypeError,
|
|
29
27
|
packSolutionAsync,
|
|
30
28
|
readSolutionFileAsUint8Array,
|
|
31
29
|
resolveSdkLogLevel,
|
|
32
30
|
validateGovernanceOptions
|
|
33
|
-
} from "./packager-tool-
|
|
31
|
+
} from "./packager-tool-n4nfqj99.js";
|
|
32
|
+
import {
|
|
33
|
+
prepareSolutionResources
|
|
34
|
+
} from "./packager-tool-7znqtw3f.js";
|
|
35
|
+
import {
|
|
36
|
+
ensurePackagerTools,
|
|
37
|
+
isUnpackableProjectTypeError,
|
|
38
|
+
toolVerbForProjectType
|
|
39
|
+
} from "./packager-tool-k4mskzww.js";
|
|
34
40
|
import {
|
|
35
41
|
publishSolutionAsync
|
|
36
|
-
} from "./packager-tool-
|
|
42
|
+
} from "./packager-tool-htag6yh5.js";
|
|
37
43
|
import {
|
|
38
44
|
Configuration,
|
|
39
45
|
PipelinesApi,
|
|
@@ -41,7 +47,7 @@ import {
|
|
|
41
47
|
feedScopeInitOverride,
|
|
42
48
|
listSelectablePublishLocations,
|
|
43
49
|
resolveFeedScope
|
|
44
|
-
} from "./packager-tool-
|
|
50
|
+
} from "./packager-tool-cp07fhx3.js";
|
|
45
51
|
import {
|
|
46
52
|
Configuration as Configuration2,
|
|
47
53
|
DeploymentActivationStatus,
|
|
@@ -59,7 +65,7 @@ import {
|
|
|
59
65
|
overwriteSolution,
|
|
60
66
|
searchPackageVersions,
|
|
61
67
|
solutionExistsOnStudioWeb
|
|
62
|
-
} from "./packager-tool-
|
|
68
|
+
} from "./packager-tool-mj5p341c.js";
|
|
63
69
|
import {
|
|
64
70
|
Tokens,
|
|
65
71
|
applyEntryPointEnhancementAsync,
|
|
@@ -71,25 +77,35 @@ import {
|
|
|
71
77
|
findMatchingLocalResource,
|
|
72
78
|
findProjectFile,
|
|
73
79
|
findResourceByKeyInRcs,
|
|
80
|
+
hasAnyTemplateRow,
|
|
81
|
+
hasBareTemplateRow,
|
|
74
82
|
isMissingProjectTypeError,
|
|
75
83
|
isProjectManifestError,
|
|
76
84
|
normalizeFolderPath,
|
|
85
|
+
normalizeResourceFileCasing,
|
|
77
86
|
readProjectFile,
|
|
78
87
|
readSolutionFile,
|
|
79
88
|
resolveSolutionFilePath,
|
|
80
89
|
resourceRefreshAsync,
|
|
90
|
+
resourceRemoteSyncAsync,
|
|
81
91
|
restoreSolutionFile,
|
|
92
|
+
saveCasingNormalized,
|
|
82
93
|
searchRcsResources,
|
|
83
|
-
syncAndLog,
|
|
84
94
|
syncResourcesFromBindings,
|
|
85
95
|
writeSolutionFile
|
|
86
|
-
} from "./packager-tool-
|
|
96
|
+
} from "./packager-tool-bkwnetqn.js";
|
|
87
97
|
import {
|
|
88
98
|
ToolResult
|
|
89
99
|
} from "./packager-tool-nzghfa48.js";
|
|
90
100
|
import {
|
|
91
101
|
getSolutionAuthContext
|
|
92
|
-
} from "./packager-tool-
|
|
102
|
+
} from "./packager-tool-2syrt51a.js";
|
|
103
|
+
import {
|
|
104
|
+
getLoginStatusAsync,
|
|
105
|
+
resolveSolutionDir,
|
|
106
|
+
toPortableRelativePath,
|
|
107
|
+
updateUipxSolutionId
|
|
108
|
+
} from "./packager-tool-3jrq7smt.js";
|
|
93
109
|
import {
|
|
94
110
|
DEFAULT_PAGE_SIZE,
|
|
95
111
|
Option,
|
|
@@ -97,13 +113,13 @@ import {
|
|
|
97
113
|
Pagination,
|
|
98
114
|
PollOutcome,
|
|
99
115
|
RESULTS,
|
|
116
|
+
carriedErrorCode,
|
|
100
117
|
carriedInstructions,
|
|
101
118
|
catchError,
|
|
102
119
|
createHiddenDeprecatedTenantOption,
|
|
103
120
|
extractErrorDetails,
|
|
104
121
|
extractErrorMessage,
|
|
105
122
|
getFileSystem,
|
|
106
|
-
getLoginStatusAsync,
|
|
107
123
|
isGuid,
|
|
108
124
|
isPreviewBuild,
|
|
109
125
|
logger,
|
|
@@ -115,14 +131,13 @@ import {
|
|
|
115
131
|
processContext,
|
|
116
132
|
registerPackageMetadataOptions,
|
|
117
133
|
requireConfirmation,
|
|
134
|
+
resolveDeprecatedOptionAlias,
|
|
118
135
|
resolveEnvReference,
|
|
119
|
-
resolveSolutionDir,
|
|
120
|
-
toPortableRelativePath,
|
|
121
136
|
trackShipSucceeded,
|
|
122
137
|
unsupportedSolutionProjectType,
|
|
123
|
-
|
|
138
|
+
warnDeprecatedOptionAlias,
|
|
124
139
|
withCompleter
|
|
125
|
-
} from "./packager-tool-
|
|
140
|
+
} from "./packager-tool-0f0wt9vh.js";
|
|
126
141
|
import {
|
|
127
142
|
strFromU8,
|
|
128
143
|
unzip,
|
|
@@ -134,8 +149,9 @@ import {
|
|
|
134
149
|
// package.json
|
|
135
150
|
var package_default = {
|
|
136
151
|
name: "@uipath/solution-tool",
|
|
152
|
+
author: "UiPath",
|
|
137
153
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
138
|
-
version: "1.
|
|
154
|
+
version: "1.203.0-preview.160",
|
|
139
155
|
description: "Create, pack, publish, and deploy UiPath Automation Solutions.",
|
|
140
156
|
repository: {
|
|
141
157
|
type: "git",
|
|
@@ -198,7 +214,7 @@ var package_default = {
|
|
|
198
214
|
"@uipath/packager-tool-connector": "workspace:*",
|
|
199
215
|
"@uipath/pipelines-sdk": "workspace:*",
|
|
200
216
|
"@uipath/project-executor": "workspace:*",
|
|
201
|
-
"@uipath/resource-builder-sdk": "
|
|
217
|
+
"@uipath/resource-builder-sdk": "2025.11.0-alpha5891-4020",
|
|
202
218
|
"@uipath/resource-builder-tool": "2025.11.0-alpha4535-3530",
|
|
203
219
|
"@uipath/solution-packager": "workspace:*",
|
|
204
220
|
"@uipath/solution-sdk": "workspace:*",
|
|
@@ -1634,8 +1650,8 @@ async function writeMissingBriefingFilesAsync(solutionDir) {
|
|
|
1634
1650
|
return written;
|
|
1635
1651
|
}
|
|
1636
1652
|
|
|
1637
|
-
// src/
|
|
1638
|
-
function resolveZipEntryPath(fs,
|
|
1653
|
+
// ../common/src/zip.ts
|
|
1654
|
+
function resolveZipEntryPath(fs, root, entryName) {
|
|
1639
1655
|
if (entryName.includes("\x00")) {
|
|
1640
1656
|
throw new Error(`Invalid zip entry path: ${entryName}`);
|
|
1641
1657
|
}
|
|
@@ -1643,24 +1659,51 @@ function resolveZipEntryPath(fs, destinationDir, entryName) {
|
|
|
1643
1659
|
if (normalizedEntry.startsWith("/")) {
|
|
1644
1660
|
throw new Error(`Unsafe absolute zip entry path: ${entryName}`);
|
|
1645
1661
|
}
|
|
1646
|
-
const root = fs.path.resolve(destinationDir);
|
|
1647
1662
|
const target = fs.path.resolve(root, normalizedEntry);
|
|
1648
|
-
|
|
1649
|
-
if (relative.startsWith("..") || fs.path.isAbsolute(relative)) {
|
|
1663
|
+
if (!isUnder(fs, root, target)) {
|
|
1650
1664
|
throw new Error(`Unsafe zip entry path: ${entryName}`);
|
|
1651
1665
|
}
|
|
1652
1666
|
return target;
|
|
1653
1667
|
}
|
|
1668
|
+
function isUnder(fs, root, path) {
|
|
1669
|
+
const relative = fs.path.relative(root, path);
|
|
1670
|
+
return relative === "" || !relative.startsWith("..") && !fs.path.isAbsolute(relative);
|
|
1671
|
+
}
|
|
1672
|
+
async function assertNoEscapeThroughSymlink(fs, lexicalRoot, realRoot, path, entryName) {
|
|
1673
|
+
const resolved = await fs.realpath(path);
|
|
1674
|
+
if (isUnder(fs, realRoot, resolved) || isUnder(fs, lexicalRoot, resolved)) {
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
throw new Error(`Unsafe zip entry path (escapes via a symlink at the destination): ${entryName}`);
|
|
1678
|
+
}
|
|
1679
|
+
async function mkdirUnderRoot(fs, lexicalRoot, realRoot, dir, entryName) {
|
|
1680
|
+
const relative = fs.path.relative(lexicalRoot, dir);
|
|
1681
|
+
if (relative === "") {
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
let current = lexicalRoot;
|
|
1685
|
+
for (const segment of relative.split(/[\\/]/)) {
|
|
1686
|
+
if (segment === "") {
|
|
1687
|
+
continue;
|
|
1688
|
+
}
|
|
1689
|
+
current = fs.path.join(current, segment);
|
|
1690
|
+
await fs.mkdir(current);
|
|
1691
|
+
await assertNoEscapeThroughSymlink(fs, lexicalRoot, realRoot, current, entryName);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1654
1694
|
async function extractZipDataToDir(fs, zipData, destinationDir) {
|
|
1655
1695
|
await fs.mkdir(destinationDir);
|
|
1696
|
+
const lexicalRoot = fs.path.resolve(destinationDir);
|
|
1697
|
+
const realRoot = await fs.realpath(lexicalRoot);
|
|
1656
1698
|
const entries = unzipSync(zipData);
|
|
1657
1699
|
for (const [entryName, content] of Object.entries(entries)) {
|
|
1658
|
-
const target = resolveZipEntryPath(fs,
|
|
1700
|
+
const target = resolveZipEntryPath(fs, lexicalRoot, entryName);
|
|
1659
1701
|
if (entryName.endsWith("/")) {
|
|
1660
|
-
await fs
|
|
1702
|
+
await mkdirUnderRoot(fs, lexicalRoot, realRoot, target, entryName);
|
|
1661
1703
|
continue;
|
|
1662
1704
|
}
|
|
1663
|
-
await
|
|
1705
|
+
await mkdirUnderRoot(fs, lexicalRoot, realRoot, fs.path.dirname(target), entryName);
|
|
1706
|
+
await assertNoEscapeThroughSymlink(fs, lexicalRoot, realRoot, target, entryName);
|
|
1664
1707
|
await fs.writeFile(target, content);
|
|
1665
1708
|
}
|
|
1666
1709
|
}
|
|
@@ -1672,6 +1715,8 @@ async function extractArchive(archivePath, destinationDir) {
|
|
|
1672
1715
|
}
|
|
1673
1716
|
await extractZipDataToDir(fs, data, destinationDir);
|
|
1674
1717
|
}
|
|
1718
|
+
|
|
1719
|
+
// src/services/archive-extract.ts
|
|
1675
1720
|
var SOLUTION_STORAGE_ENTRY = "SolutionStorage.json";
|
|
1676
1721
|
function isRootUipxEntry(name) {
|
|
1677
1722
|
return !name.includes("/") && name.endsWith(".uipx");
|
|
@@ -1987,7 +2032,7 @@ var SOLUTION_PACK_EXAMPLES = [
|
|
|
1987
2032
|
},
|
|
1988
2033
|
{
|
|
1989
2034
|
Description: "Analyze the RPA projects against the governance policy published in AutomationOps for the signed-in tenant. The value is the product whose policy is downloaded — pass StudioWeb for the default one.",
|
|
1990
|
-
Command: "uip solution pack ./my-solution ./dist --version 1.2.0 --
|
|
2035
|
+
Command: "uip solution pack ./my-solution ./dist --version 1.2.0 --governance-product Development",
|
|
1991
2036
|
Output: {
|
|
1992
2037
|
Code: "SolutionPack",
|
|
1993
2038
|
Data: {
|
|
@@ -1998,7 +2043,7 @@ var SOLUTION_PACK_EXAMPLES = [
|
|
|
1998
2043
|
}
|
|
1999
2044
|
];
|
|
2000
2045
|
var registerPackCommand = (program) => {
|
|
2001
|
-
const command = program.command("pack").description("Pack a UiPath solution into a deployable .zip package. Accepts a solution directory (containing .uipx) or a .uis file. Output is used with 'solution publish' to upload to UiPath. Pass --dry-run to check that the solution packs without producing a package.").argument("<solutionPath>", "Path to a solution directory (containing .uipx) or a .uis file").argument("[output-path]", "Output directory where the packed solution will be saved. Required unless --dry-run is set.").option("-n, --name <name>", "Package name (default: solution folder name or .uis file name)").option("-v, --version <version>", "Package version (default: 1.0.0)", "1.0.0").option("--nuget-sources-config-path <path>", "Path to NuGet sources configuration file").option("--exclude-configured-sources", "Resolve project dependencies only from the tenant feeds and any --nuget-sources-config-path. Drops the built-in UiPath and nuget.org feeds, so a dependency that is not on those feeds fails to restore.").option("--feed-folder <name>", "Resolve project dependencies from this Orchestrator folder's library feed instead of every tenant feed. Accepts a folder name or fully qualified path.").option("--signing-certificate-path <path>", "Path to .pfx certificate file used to sign each packed project .nupkg").option("--signing-certificate-password <password>", "Certificate password. Use env.ENV_NAME to read from an environment variable.").option("--signing-timestamp-server <url>", "Timestamp server URL").option("--skip-analyze", "Skip the workflow analyzer for every RPA project in the solution. Compilation and validation still run.").
|
|
2046
|
+
const command = program.command("pack").description("Pack a UiPath solution into a deployable .zip package. Accepts a solution directory (containing .uipx) or a .uis file. Output is used with 'solution publish' to upload to UiPath. Pass --dry-run to check that the solution packs without producing a package.").argument("<solutionPath>", "Path to a solution directory (containing .uipx) or a .uis file").argument("[output-path]", "Output directory where the packed solution will be saved. Required unless --dry-run is set.").option("-n, --name <name>", "Package name (default: solution folder name or .uis file name)").option("-v, --version <version>", "Package version (default: 1.0.0)", "1.0.0").option("--nuget-sources-config-path <path>", "Path to NuGet sources configuration file").option("--exclude-configured-sources", "Resolve project dependencies only from the tenant feeds and any --nuget-sources-config-path. Drops the built-in UiPath and nuget.org feeds, so a dependency that is not on those feeds fails to restore.").option("--feed-folder <name>", "Resolve project dependencies from this Orchestrator folder's library feed instead of every tenant feed. Accepts a folder name or fully qualified path.").option("--signing-certificate-path <path>", "Path to .pfx certificate file used to sign each packed project .nupkg").option("--signing-certificate-password <password>", "Certificate password. Use env.ENV_NAME to read from an environment variable.").option("--signing-timestamp-server <url>", "Timestamp server URL").option("--skip-analyze", "Skip the workflow analyzer for every RPA project in the solution. Compilation and validation still run.").option("--governance-file-path <path>", "Analyze every RPA project against this local governance policy file, instead of the analyzer rules shipped with the WorkflowCompiler. When you are signed in the tenant is asked first — about StudioWeb unless --governance-product names another product — and this file is refused if the tenant publishes a policy of its own.").option("--governance-product <product>", "Analyze every RPA project against the governance policy published in AutomationOps for the signed-in tenant. The value is the product whose policy is downloaded, e.g. StudioWeb, Development, Business.").addOption(new Option("--automation-ops-profile <profile>").hideHelp());
|
|
2002
2047
|
registerPackageMetadataOptions(command).option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", parseInt, 10).option("--dry-run", "Run the full pack pipeline against a temporary directory and discard the output. Catches pack-time failures; does not inspect the produced package contents.").examples(SOLUTION_PACK_EXAMPLES).trackedAction(processContext, async (solutionPath, outputPath, options) => {
|
|
2003
2048
|
if (!options.dryRun && outputPath === undefined) {
|
|
2004
2049
|
OutputFormatter.error({
|
|
@@ -2009,9 +2054,27 @@ var registerPackCommand = (program) => {
|
|
|
2009
2054
|
processContext.exit(1);
|
|
2010
2055
|
return;
|
|
2011
2056
|
}
|
|
2057
|
+
const product = resolveDeprecatedOptionAlias({
|
|
2058
|
+
preferredValue: options.governanceProduct,
|
|
2059
|
+
deprecatedValue: options.automationOpsProfile,
|
|
2060
|
+
preferredFlag: "--governance-product",
|
|
2061
|
+
deprecatedFlag: "--automation-ops-profile"
|
|
2062
|
+
});
|
|
2063
|
+
if (product.error) {
|
|
2064
|
+
OutputFormatter.error({
|
|
2065
|
+
Result: RESULTS.Failure,
|
|
2066
|
+
Message: product.error.message,
|
|
2067
|
+
Instructions: product.error.instructions
|
|
2068
|
+
});
|
|
2069
|
+
processContext.exit(1);
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if (product.usedDeprecated) {
|
|
2073
|
+
warnDeprecatedOptionAlias("--automation-ops-profile", "--governance-product");
|
|
2074
|
+
}
|
|
2012
2075
|
const governanceError = validateGovernanceOptions({
|
|
2013
2076
|
governanceFilePath: options.governanceFilePath,
|
|
2014
|
-
|
|
2077
|
+
governanceProduct: product.value
|
|
2015
2078
|
});
|
|
2016
2079
|
if (governanceError) {
|
|
2017
2080
|
OutputFormatter.error({
|
|
@@ -2037,7 +2100,7 @@ var registerPackCommand = (program) => {
|
|
|
2037
2100
|
signingTimestampServer: options.signingTimestampServer,
|
|
2038
2101
|
skipAnalyze: options.skipAnalyze,
|
|
2039
2102
|
governanceFilePath: options.governanceFilePath,
|
|
2040
|
-
|
|
2103
|
+
governanceProduct: product.value,
|
|
2041
2104
|
...mapPackageMetadataOptions(options)
|
|
2042
2105
|
};
|
|
2043
2106
|
await service.execute(solutionPath, packOptions, processContext);
|
|
@@ -2454,22 +2517,6 @@ var registerPackagesCommand = (program) => {
|
|
|
2454
2517
|
// src/commands/project-add.ts
|
|
2455
2518
|
import { randomUUID } from "node:crypto";
|
|
2456
2519
|
|
|
2457
|
-
// src/services/appv2-manifest.ts
|
|
2458
|
-
var WEB_APP_MANIFEST = "webAppManifest.json";
|
|
2459
|
-
async function resolveAppV2SubType(projectDir) {
|
|
2460
|
-
const fs = getFileSystem();
|
|
2461
|
-
const manifestPath = fs.path.join(projectDir, WEB_APP_MANIFEST);
|
|
2462
|
-
if (!await fs.exists(manifestPath))
|
|
2463
|
-
return "Coded";
|
|
2464
|
-
const [readError, raw] = await catchError(fs.readFile(manifestPath, "utf-8"));
|
|
2465
|
-
if (readError || !raw)
|
|
2466
|
-
return "Coded";
|
|
2467
|
-
const [parseError, manifest] = catchError(() => JSON.parse(raw));
|
|
2468
|
-
if (parseError)
|
|
2469
|
-
return "Coded";
|
|
2470
|
-
return manifest?.config?.isActionApp === true ? "CodedAction" : "Coded";
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
2520
|
// src/commands/project-command-utils.ts
|
|
2474
2521
|
function rejectUnsupportedProjectType(projectType, failureMessage) {
|
|
2475
2522
|
const reason = unsupportedSolutionProjectType(projectType);
|
|
@@ -2490,6 +2537,17 @@ function projectManifestInstructions(fileName, readProjectError, verb) {
|
|
|
2490
2537
|
}
|
|
2491
2538
|
return `${readProjectError.message} If this is a coded app, scaffold it with 'uip codedapp init <project-path>' — that writes the project.uiproj this command registers — then run 'uip solution projects ${verb} <project-path>' again.`;
|
|
2492
2539
|
}
|
|
2540
|
+
function resourcesPendingForProjectType(projectType) {
|
|
2541
|
+
return !hasBareTemplateRow(projectType) && hasAnyTemplateRow(projectType);
|
|
2542
|
+
}
|
|
2543
|
+
function hostGeneratesResources(projectType) {
|
|
2544
|
+
return hasBareTemplateRow(projectType);
|
|
2545
|
+
}
|
|
2546
|
+
function resourcesPendingWarning(projectType) {
|
|
2547
|
+
const verb = toolVerbForProjectType(projectType);
|
|
2548
|
+
const needs = verb ? `that needs the '${verb}' tool installed ('uip tools install ${verb}')` : "that needs the tool that owns this project type installed";
|
|
2549
|
+
return `No solution resources were generated for this project yet. Run 'uip solution resources refresh' to create them — ${needs}. 'uip solution pack' and 'uip solution upload' do it too.`;
|
|
2550
|
+
}
|
|
2493
2551
|
|
|
2494
2552
|
// src/commands/project-add.ts
|
|
2495
2553
|
var PROJECT_ADD_EXAMPLES = [
|
|
@@ -2501,7 +2559,8 @@ var PROJECT_ADD_EXAMPLES = [
|
|
|
2501
2559
|
Data: {
|
|
2502
2560
|
Status: "Added successfully",
|
|
2503
2561
|
Project: "my-project/project.uiproj",
|
|
2504
|
-
Solution: "/workspace/my-solution/my-solution.uipx"
|
|
2562
|
+
Solution: "/workspace/my-solution/my-solution.uipx",
|
|
2563
|
+
ResourcesPending: false
|
|
2505
2564
|
}
|
|
2506
2565
|
}
|
|
2507
2566
|
}
|
|
@@ -2625,8 +2684,8 @@ var registerProjectAddCommand = (project) => {
|
|
|
2625
2684
|
processContext.exit(1);
|
|
2626
2685
|
return;
|
|
2627
2686
|
}
|
|
2628
|
-
const
|
|
2629
|
-
const createError = await createProjectInSolutionBuilder(solutionDir, projectId, projectName, parsedProject.projectType
|
|
2687
|
+
const resourcesPending = resourcesPendingForProjectType(parsedProject.projectType);
|
|
2688
|
+
const createError = hostGeneratesResources(parsedProject.projectType) ? await createProjectInSolutionBuilder(solutionDir, projectId, projectName, parsedProject.projectType) : null;
|
|
2630
2689
|
if (createError) {
|
|
2631
2690
|
const restoreError = await restoreSolutionFile(resolvedSolutionFile, originalSolutionContent);
|
|
2632
2691
|
OutputFormatter.error({
|
|
@@ -2644,13 +2703,17 @@ Rollback failed: ${restoreError.message}` : createError.message
|
|
|
2644
2703
|
logger.warn(warning);
|
|
2645
2704
|
}
|
|
2646
2705
|
}
|
|
2706
|
+
if (resourcesPending) {
|
|
2707
|
+
logger.warn(resourcesPendingWarning(parsedProject.projectType));
|
|
2708
|
+
}
|
|
2647
2709
|
OutputFormatter.success({
|
|
2648
2710
|
Result: RESULTS.Success,
|
|
2649
2711
|
Code: "ProjectAdd",
|
|
2650
2712
|
Data: {
|
|
2651
2713
|
Status: "Added successfully",
|
|
2652
2714
|
Project: projectRelativePath,
|
|
2653
|
-
Solution: resolvedSolutionFile
|
|
2715
|
+
Solution: resolvedSolutionFile,
|
|
2716
|
+
ResourcesPending: resourcesPending
|
|
2654
2717
|
}
|
|
2655
2718
|
});
|
|
2656
2719
|
});
|
|
@@ -2667,7 +2730,8 @@ var PROJECT_IMPORT_EXAMPLES = [
|
|
|
2667
2730
|
Data: {
|
|
2668
2731
|
Status: "Imported successfully",
|
|
2669
2732
|
Project: "external-project/project.uiproj",
|
|
2670
|
-
Solution: "/workspace/my-solution/my-solution.uipx"
|
|
2733
|
+
Solution: "/workspace/my-solution/my-solution.uipx",
|
|
2734
|
+
ResourcesPending: false
|
|
2671
2735
|
}
|
|
2672
2736
|
}
|
|
2673
2737
|
}
|
|
@@ -2811,8 +2875,8 @@ var registerProjectImportCommand = (project) => {
|
|
|
2811
2875
|
await catchError(fs.rm(targetProjectPath));
|
|
2812
2876
|
await catchError(fs.writeFile(resolvedSolutionFile, originalSolutionContent));
|
|
2813
2877
|
};
|
|
2814
|
-
const
|
|
2815
|
-
const createError = await createProjectInSolutionBuilder(solutionDir, projectId, projectName, parsedProject.projectType
|
|
2878
|
+
const resourcesPending = resourcesPendingForProjectType(parsedProject.projectType);
|
|
2879
|
+
const createError = hostGeneratesResources(parsedProject.projectType) ? await createProjectInSolutionBuilder(solutionDir, projectId, projectName, parsedProject.projectType) : null;
|
|
2816
2880
|
if (createError) {
|
|
2817
2881
|
await rollback();
|
|
2818
2882
|
OutputFormatter.error({
|
|
@@ -2827,13 +2891,17 @@ var registerProjectImportCommand = (project) => {
|
|
|
2827
2891
|
for (const warning of syncResult.warnings) {
|
|
2828
2892
|
logger.warn(warning);
|
|
2829
2893
|
}
|
|
2894
|
+
if (resourcesPending) {
|
|
2895
|
+
logger.warn(resourcesPendingWarning(parsedProject.projectType));
|
|
2896
|
+
}
|
|
2830
2897
|
OutputFormatter.success({
|
|
2831
2898
|
Result: RESULTS.Success,
|
|
2832
2899
|
Code: "ProjectImport",
|
|
2833
2900
|
Data: {
|
|
2834
2901
|
Status: "Imported successfully",
|
|
2835
2902
|
Project: projectRelativePath,
|
|
2836
|
-
Solution: resolvedSolutionFile
|
|
2903
|
+
Solution: resolvedSolutionFile,
|
|
2904
|
+
ResourcesPending: resourcesPending
|
|
2837
2905
|
}
|
|
2838
2906
|
});
|
|
2839
2907
|
});
|
|
@@ -3753,6 +3821,7 @@ var registerResourceAddCommand = (resource) => {
|
|
|
3753
3821
|
processContext.exit(1);
|
|
3754
3822
|
return;
|
|
3755
3823
|
}
|
|
3824
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
3756
3825
|
const [builderError, builder] = await catchError(services.getSolutionBuilder(resolvedPath));
|
|
3757
3826
|
if (builderError) {
|
|
3758
3827
|
OutputFormatter.error({
|
|
@@ -3798,7 +3867,10 @@ var registerResourceAddCommand = (resource) => {
|
|
|
3798
3867
|
Data: outcome.data
|
|
3799
3868
|
});
|
|
3800
3869
|
} finally {
|
|
3801
|
-
const
|
|
3870
|
+
const disposeError = await saveCasingNormalized(builder);
|
|
3871
|
+
if (!disposeError) {
|
|
3872
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
3873
|
+
}
|
|
3802
3874
|
if (disposeError) {
|
|
3803
3875
|
OutputFormatter.error({
|
|
3804
3876
|
Result: RESULTS.Failure,
|
|
@@ -4062,7 +4134,25 @@ function toResourceAddData(resource, folders, source, status) {
|
|
|
4062
4134
|
}
|
|
4063
4135
|
|
|
4064
4136
|
// src/commands/resource-edit.ts
|
|
4065
|
-
var
|
|
4137
|
+
var RESOURCE_KEY_REGEX = /^[A-Za-z0-9._:-]{1,256}$/;
|
|
4138
|
+
var REMOTE_FAILURE_MESSAGE = {
|
|
4139
|
+
solution_not_found: "Failed to edit resource",
|
|
4140
|
+
not_a_solution: "Failed to edit resource",
|
|
4141
|
+
auth_failed: "Failed to authenticate",
|
|
4142
|
+
resource_not_found: "Resource not found in solution",
|
|
4143
|
+
no_remote_reference: "Resource has no cloud definition to sync from",
|
|
4144
|
+
comparison_unavailable: "Could not read the cloud definition to compare against",
|
|
4145
|
+
sync_failed: "Failed to sync resource from the cloud definition",
|
|
4146
|
+
save_failed: "Resource edit completed but the solution could not be saved"
|
|
4147
|
+
};
|
|
4148
|
+
var REMOTE_FAILURE_CODE = {
|
|
4149
|
+
solution_not_found: "not_found",
|
|
4150
|
+
not_a_solution: "invalid_argument",
|
|
4151
|
+
auth_failed: "authentication_required",
|
|
4152
|
+
resource_not_found: "not_found",
|
|
4153
|
+
no_remote_reference: "invalid_argument",
|
|
4154
|
+
comparison_unavailable: "not_found"
|
|
4155
|
+
};
|
|
4066
4156
|
var NOT_FOUND_PATTERN = /not found/i;
|
|
4067
4157
|
var RESOURCE_EDIT_EXAMPLES = [
|
|
4068
4158
|
{
|
|
@@ -4107,10 +4197,36 @@ var RESOURCE_EDIT_EXAMPLES = [
|
|
|
4107
4197
|
apiVersion: "orchestrator.uipath.com/v1"
|
|
4108
4198
|
}
|
|
4109
4199
|
}
|
|
4200
|
+
},
|
|
4201
|
+
{
|
|
4202
|
+
Description: "Show what the cloud definition would overwrite, without writing (no --force)",
|
|
4203
|
+
Command: "uip solution resources edit 8f3a1b2c-... --source remote",
|
|
4204
|
+
Output: {
|
|
4205
|
+
Code: "ResourceRemoteDrift",
|
|
4206
|
+
Data: {
|
|
4207
|
+
Key: "8f3a1b2c-1234-4abc-9def-0123456789ab",
|
|
4208
|
+
Changed: ["description", "fields"],
|
|
4209
|
+
Applied: false,
|
|
4210
|
+
Status: "2 properties differ from the cloud definition. Re-run with --force to overwrite the local values."
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
},
|
|
4214
|
+
{
|
|
4215
|
+
Description: "Pull the current cloud definition over the local one (overwrites local edits)",
|
|
4216
|
+
Command: "uip solution resources edit 8f3a1b2c-... --source remote --force",
|
|
4217
|
+
Output: {
|
|
4218
|
+
Code: "ResourceEdited",
|
|
4219
|
+
Data: {
|
|
4220
|
+
Key: "8f3a1b2c-1234-4abc-9def-0123456789ab",
|
|
4221
|
+
Changed: ["fields"],
|
|
4222
|
+
Applied: true,
|
|
4223
|
+
Status: "Overwrote 1 property with the cloud definition"
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4110
4226
|
}
|
|
4111
4227
|
];
|
|
4112
4228
|
var registerResourceEditCommand = (resource) => {
|
|
4113
|
-
resource.command("edit").description("Edit a resource's spec properties by key. Pass --patch with a JSON object " + "of property → value; the JSON is merged into the existing spec. Properties " + "the SDK metadata marks as reference/read-only/unknown are silently ignored. " + "Use 'uip solution resources get <key>' to inspect the current spec; the " + "get↔edit shapes match, so a round-trip is straightforward.").argument("<resource-key>", "Solution resource key (GUID)").option("--patch <json>", `JSON object of spec property → value (e.g. '{"retentionPeriod":14}'). Pass '-' to read the JSON from stdin.`).option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").examples(RESOURCE_EDIT_EXAMPLES).trackedAction(processContext, async (resourceKey, options) => {
|
|
4229
|
+
resource.command("edit").description("Edit a resource's spec properties by key. Pass --patch with a JSON object " + "of property → value; the JSON is merged into the existing spec. Properties " + "the SDK metadata marks as reference/read-only/unknown are silently ignored. " + "Use 'uip solution resources get <key>' to inspect the current spec; the " + "get↔edit shapes match, so a round-trip is straightforward. " + "Pass --source remote instead of --patch to take the values from the cloud " + "definition the resource was imported from — the only way to pick up a change " + "made in Orchestrator or Data Fabric after the import, since 'resources refresh' " + "never overwrites an imported resource.").argument("<resource-key>", "Solution resource key (a GUID, or a compound key such as MyFunction.api.MyFunction.1:1.0.0)").option("--patch <json>", `JSON object of spec property → value (e.g. '{"retentionPeriod":14}'). Pass '-' to read the JSON from stdin.`).option("--source <source>", "Where the new values come from: 'local' (default, use --patch) or 'remote' (the cloud definition this resource was imported from)", "local").option("--force", "With --source remote, write the cloud definition over the local one. Without it the command only reports what would change and writes nothing.").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10). Only used by --source remote.", "10").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").examples(RESOURCE_EDIT_EXAMPLES).trackedAction(processContext, async (resourceKey, options) => {
|
|
4114
4230
|
if (!resourceKey || resourceKey.trim().length === 0) {
|
|
4115
4231
|
OutputFormatter.error({
|
|
4116
4232
|
Result: RESULTS.Failure,
|
|
@@ -4120,15 +4236,53 @@ var registerResourceEditCommand = (resource) => {
|
|
|
4120
4236
|
processContext.exit(1);
|
|
4121
4237
|
return;
|
|
4122
4238
|
}
|
|
4123
|
-
if (!
|
|
4239
|
+
if (!RESOURCE_KEY_REGEX.test(resourceKey)) {
|
|
4124
4240
|
OutputFormatter.error({
|
|
4125
4241
|
Result: RESULTS.Failure,
|
|
4126
|
-
Message: "<resource-key>
|
|
4127
|
-
Instructions: "Resource keys
|
|
4242
|
+
Message: "<resource-key> contains unsupported characters",
|
|
4243
|
+
Instructions: "Resource keys use letters, digits, and '. _ - :' only. Use 'uip solution resources list' to find a valid key."
|
|
4128
4244
|
});
|
|
4129
4245
|
processContext.exit(1);
|
|
4130
4246
|
return;
|
|
4131
4247
|
}
|
|
4248
|
+
const source = (options.source ?? "local").toLowerCase();
|
|
4249
|
+
if (source !== "local" && source !== "remote") {
|
|
4250
|
+
OutputFormatter.error({
|
|
4251
|
+
Result: RESULTS.Failure,
|
|
4252
|
+
Message: `Invalid --source value "${options.source}"`,
|
|
4253
|
+
Instructions: "Use --source local (with --patch) or --source remote.",
|
|
4254
|
+
ErrorCode: "invalid_argument",
|
|
4255
|
+
Retry: "RetryWillNotFix"
|
|
4256
|
+
});
|
|
4257
|
+
processContext.exit(1);
|
|
4258
|
+
return;
|
|
4259
|
+
}
|
|
4260
|
+
if (source === "local" && options.force === true) {
|
|
4261
|
+
OutputFormatter.error({
|
|
4262
|
+
Result: RESULTS.Failure,
|
|
4263
|
+
Message: "--force only applies to --source remote",
|
|
4264
|
+
Instructions: "Drop --force, or add --source remote to overwrite the local spec with the cloud definition.",
|
|
4265
|
+
ErrorCode: "invalid_argument",
|
|
4266
|
+
Retry: "RetryWillNotFix"
|
|
4267
|
+
});
|
|
4268
|
+
processContext.exit(1);
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4271
|
+
if (source === "remote") {
|
|
4272
|
+
if (options.patch !== undefined) {
|
|
4273
|
+
OutputFormatter.error({
|
|
4274
|
+
Result: RESULTS.Failure,
|
|
4275
|
+
Message: "--patch cannot be combined with --source remote",
|
|
4276
|
+
Instructions: "Drop --patch to take the values from the cloud definition, or drop --source remote to apply your own values.",
|
|
4277
|
+
ErrorCode: "invalid_argument",
|
|
4278
|
+
Retry: "RetryWillNotFix"
|
|
4279
|
+
});
|
|
4280
|
+
processContext.exit(1);
|
|
4281
|
+
return;
|
|
4282
|
+
}
|
|
4283
|
+
await handleRemoteSourceAsync(resourceKey, options);
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4132
4286
|
const [parseError, properties] = await catchError(buildProperties(options));
|
|
4133
4287
|
if (parseError) {
|
|
4134
4288
|
OutputFormatter.error({
|
|
@@ -4179,6 +4333,7 @@ var registerResourceEditCommand = (resource) => {
|
|
|
4179
4333
|
processContext.exit(1);
|
|
4180
4334
|
return;
|
|
4181
4335
|
}
|
|
4336
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
4182
4337
|
const [builderError, builder] = await catchError(services.getSolutionBuilder(resolvedPath));
|
|
4183
4338
|
if (builderError) {
|
|
4184
4339
|
OutputFormatter.error({
|
|
@@ -4209,7 +4364,10 @@ var registerResourceEditCommand = (resource) => {
|
|
|
4209
4364
|
Data: config
|
|
4210
4365
|
});
|
|
4211
4366
|
} finally {
|
|
4212
|
-
const
|
|
4367
|
+
const disposeError = await saveCasingNormalized(builder);
|
|
4368
|
+
if (!disposeError) {
|
|
4369
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
4370
|
+
}
|
|
4213
4371
|
if (disposeError) {
|
|
4214
4372
|
OutputFormatter.error({
|
|
4215
4373
|
Result: RESULTS.Failure,
|
|
@@ -4221,6 +4379,62 @@ var registerResourceEditCommand = (resource) => {
|
|
|
4221
4379
|
}
|
|
4222
4380
|
});
|
|
4223
4381
|
};
|
|
4382
|
+
async function handleRemoteSourceAsync(resourceKey, options) {
|
|
4383
|
+
const result = await resourceRemoteSyncAsync(options.solutionFolder ?? ".", resourceKey, {
|
|
4384
|
+
force: options.force === true,
|
|
4385
|
+
loginValidity: options.loginValidity ? parseInt(options.loginValidity, 10) : undefined
|
|
4386
|
+
});
|
|
4387
|
+
if (!result.ok) {
|
|
4388
|
+
OutputFormatter.error({
|
|
4389
|
+
Result: RESULTS.Failure,
|
|
4390
|
+
Message: REMOTE_FAILURE_MESSAGE[result.reason],
|
|
4391
|
+
Instructions: result.reason === "resource_not_found" ? `No resource with key ${resourceKey}. Use 'uip solution resources list' to see available keys.` : result.message,
|
|
4392
|
+
ErrorCode: REMOTE_FAILURE_CODE[result.reason],
|
|
4393
|
+
Retry: result.reason === "sync_failed" ? undefined : "RetryWillNotFix"
|
|
4394
|
+
});
|
|
4395
|
+
processContext.exit(1);
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
const count = result.changed.length;
|
|
4399
|
+
if (!result.applied) {
|
|
4400
|
+
if (count === 0) {
|
|
4401
|
+
OutputFormatter.success({
|
|
4402
|
+
Result: RESULTS.Success,
|
|
4403
|
+
Code: "ResourceRemoteDrift",
|
|
4404
|
+
Data: {
|
|
4405
|
+
Key: result.key,
|
|
4406
|
+
Changed: [],
|
|
4407
|
+
Applied: false,
|
|
4408
|
+
Status: "Already matches the cloud definition — nothing to overwrite"
|
|
4409
|
+
}
|
|
4410
|
+
});
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4413
|
+
OutputFormatter.error({
|
|
4414
|
+
Result: RESULTS.Failure,
|
|
4415
|
+
Message: `${count} ${count === 1 ? "property differs" : "properties differ"} from the cloud definition: ${result.changed.join(", ")}`,
|
|
4416
|
+
Instructions: `Overwriting discards the local values of ${count === 1 ? "that property" : "those properties"}. Re-run with --force to apply: uip solution resources edit ${result.key} --source remote --force`,
|
|
4417
|
+
ErrorCode: "invalid_argument",
|
|
4418
|
+
Retry: "RetryWillNotFix"
|
|
4419
|
+
});
|
|
4420
|
+
processContext.exit(1);
|
|
4421
|
+
return;
|
|
4422
|
+
}
|
|
4423
|
+
const skipped = result.skipped.length;
|
|
4424
|
+
const base = count === 0 ? "Already matched the cloud definition — nothing changed" : `Overwrote ${count} ${count === 1 ? "property" : "properties"} with the cloud definition`;
|
|
4425
|
+
OutputFormatter.success({
|
|
4426
|
+
Result: RESULTS.Success,
|
|
4427
|
+
Code: "ResourceEdited",
|
|
4428
|
+
Data: {
|
|
4429
|
+
Key: result.key,
|
|
4430
|
+
Changed: result.changed,
|
|
4431
|
+
Skipped: result.skipped,
|
|
4432
|
+
Applied: true,
|
|
4433
|
+
Status: skipped === 0 ? base : `${base}. ${skipped} ${skipped === 1 ? "property" : "properties"} could not be written and still differ (${result.skipped.join(", ")}) — the SDK does not let this resource kind set ${skipped === 1 ? "it" : "them"}.`,
|
|
4434
|
+
Spec: result.spec
|
|
4435
|
+
}
|
|
4436
|
+
});
|
|
4437
|
+
}
|
|
4224
4438
|
async function buildProperties(options) {
|
|
4225
4439
|
if (options.patch === undefined) {
|
|
4226
4440
|
return {};
|
|
@@ -4850,8 +5064,9 @@ var RESOURCE_REFRESH_EXAMPLES = [
|
|
|
4850
5064
|
Imported: 1,
|
|
4851
5065
|
Skipped: 5,
|
|
4852
5066
|
Pruned: 0,
|
|
5067
|
+
ReconciledSpecs: 1,
|
|
4853
5068
|
Warnings: [],
|
|
4854
|
-
Status: "Synced 3 resources (5 already in solution)"
|
|
5069
|
+
Status: "Synced 3 resources (5 already in solution). Refresh never overwrites an imported resource — to pull a changed cloud definition, run 'uip solution resources edit <resource-key> --source remote'."
|
|
4855
5070
|
}
|
|
4856
5071
|
}
|
|
4857
5072
|
}
|
|
@@ -4863,9 +5078,33 @@ var FAILURE_MESSAGE = {
|
|
|
4863
5078
|
sync_failed: "Failed to refresh resources"
|
|
4864
5079
|
};
|
|
4865
5080
|
var registerResourceRefreshSubcommand = (resource) => {
|
|
4866
|
-
resource.command("refresh").description("Re-scan all projects in the solution and sync
|
|
5081
|
+
resource.command("refresh").description("Re-scan all projects in the solution and sync each project's authored files into the solution resource JSONs. " + "Bindings: creates new resources for `bindings_v2.json` entries not yet in the solution, imports from Orchestrator when a matching resource exists, and removes duplicate copies of the solution's own projects that earlier runs imported from a deployed folder. " + "Project contributions: each project's owning tool reports what its authored files add to the solution resources, and refresh persists it onto the matching resource. " + "Run this after editing a project's bindings or any file the project's tool contributes from, to update the solution resource inventory. " + "Refresh is import-only for cloud resources: it never overwrites an imported resource, so local edits survive; a project's own artefact resources are rewritten from the project's files on every run. " + "To pull a cloud definition that changed after the import, use 'uip solution resources edit <resource-key> --source remote'.").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").option("--login-validity <minutes>", "Minimum minutes before token expiration to trigger a refresh (default: 10)", "10").examples(RESOURCE_REFRESH_EXAMPLES).trackedAction(processContext, async (options) => {
|
|
4867
5082
|
const loginValidityMinutes = options.loginValidity ? parseInt(options.loginValidity, 10) : undefined;
|
|
4868
|
-
const
|
|
5083
|
+
const solutionFolder = options.solutionFolder ?? ".";
|
|
5084
|
+
const fs = getFileSystem();
|
|
5085
|
+
let contributions;
|
|
5086
|
+
const [
|
|
5087
|
+
{ ensurePackagerTools: ensurePackagerTools2 },
|
|
5088
|
+
{ projectSubTypesFrom },
|
|
5089
|
+
{
|
|
5090
|
+
applyProjectContributions,
|
|
5091
|
+
collectProjectContributions,
|
|
5092
|
+
contributionErrorMessages
|
|
5093
|
+
}
|
|
5094
|
+
] = await Promise.all([
|
|
5095
|
+
import("./packager-tool-resolver-fmjr60x8.js"),
|
|
5096
|
+
import("./prepare-solution-resources-wds3r8bq.js"),
|
|
5097
|
+
import("./project-contributions-cvttys34.js")
|
|
5098
|
+
]);
|
|
5099
|
+
const resolveProjectSubTypesAsync = async () => {
|
|
5100
|
+
await ensurePackagerTools2(solutionFolder, fs);
|
|
5101
|
+
contributions = await collectProjectContributions(solutionFolder, fs);
|
|
5102
|
+
return projectSubTypesFrom(contributions);
|
|
5103
|
+
};
|
|
5104
|
+
const result = await resourceRefreshAsync(solutionFolder, {
|
|
5105
|
+
loginValidity: loginValidityMinutes,
|
|
5106
|
+
resolveProjectSubTypesAsync
|
|
5107
|
+
});
|
|
4869
5108
|
if (!result.ok) {
|
|
4870
5109
|
OutputFormatter.error({
|
|
4871
5110
|
Result: RESULTS.Failure,
|
|
@@ -4876,6 +5115,26 @@ var registerResourceRefreshSubcommand = (resource) => {
|
|
|
4876
5115
|
return;
|
|
4877
5116
|
}
|
|
4878
5117
|
const prunedNote = result.pruned > 0 ? `, ${result.pruned} duplicates removed` : "";
|
|
5118
|
+
const skippedNote = result.skipped > 0 ? " Refresh never overwrites an imported resource — to pull a changed cloud definition, run 'uip solution resources edit <resource-key> --source remote'." : "";
|
|
5119
|
+
let applied = { updated: 0, warnings: [] };
|
|
5120
|
+
if (contributions) {
|
|
5121
|
+
const [applyError, written] = await catchError(applyProjectContributions(solutionFolder, contributions, undefined, fs));
|
|
5122
|
+
if (applyError) {
|
|
5123
|
+
OutputFormatter.error({
|
|
5124
|
+
Result: RESULTS.Failure,
|
|
5125
|
+
Message: FAILURE_MESSAGE.sync_failed,
|
|
5126
|
+
Instructions: `Bindings synced, but the project contributions could not be written to the solution resources: ${applyError.message}. Fix the reported problem, then re-run 'uip solution resources refresh'.`
|
|
5127
|
+
});
|
|
5128
|
+
processContext.exit(1);
|
|
5129
|
+
return;
|
|
5130
|
+
}
|
|
5131
|
+
applied = written;
|
|
5132
|
+
}
|
|
5133
|
+
const warnings = [
|
|
5134
|
+
...result.warnings,
|
|
5135
|
+
...contributions ? contributionErrorMessages(contributions) : [],
|
|
5136
|
+
...applied.warnings
|
|
5137
|
+
];
|
|
4879
5138
|
OutputFormatter.success({
|
|
4880
5139
|
Result: RESULTS.Success,
|
|
4881
5140
|
Code: "ResourceRefresh",
|
|
@@ -4884,15 +5143,16 @@ var registerResourceRefreshSubcommand = (resource) => {
|
|
|
4884
5143
|
Imported: result.imported,
|
|
4885
5144
|
Skipped: result.skipped,
|
|
4886
5145
|
Pruned: result.pruned,
|
|
4887
|
-
|
|
4888
|
-
|
|
5146
|
+
ReconciledSpecs: applied.updated,
|
|
5147
|
+
Warnings: warnings,
|
|
5148
|
+
Status: `Synced ${result.created + result.imported} resources (${result.skipped} already in solution${prunedNote}).${skippedNote}`
|
|
4889
5149
|
}
|
|
4890
5150
|
});
|
|
4891
5151
|
});
|
|
4892
5152
|
};
|
|
4893
5153
|
|
|
4894
5154
|
// src/commands/resource-remove.ts
|
|
4895
|
-
var
|
|
5155
|
+
var RESOURCE_KEY_REGEX2 = /^[A-Za-z0-9._:-]{1,256}$/;
|
|
4896
5156
|
var RESOURCE_REMOVE_EXAMPLES = [
|
|
4897
5157
|
{
|
|
4898
5158
|
Description: "Remove a resource by its solution key",
|
|
@@ -4909,7 +5169,7 @@ var RESOURCE_REMOVE_EXAMPLES = [
|
|
|
4909
5169
|
}
|
|
4910
5170
|
];
|
|
4911
5171
|
var registerResourceRemoveCommand = (resource) => {
|
|
4912
|
-
resource.command("remove").description("Remove a resource from the solution by its key. Use 'uip solution resources list' " + "or 'uip solution resources get' to discover the key first. " + "Purely local — no auth required, doesn't touch any bindings_v2.json.").argument("<resource-key>", "Solution resource key (GUID)").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").examples(RESOURCE_REMOVE_EXAMPLES).trackedAction(processContext, async (resourceKey, options) => {
|
|
5172
|
+
resource.command("remove").description("Remove a resource from the solution by its key. Use 'uip solution resources list' " + "or 'uip solution resources get' to discover the key first. " + "Purely local — no auth required, doesn't touch any bindings_v2.json.").argument("<resource-key>", "Solution resource key (a GUID, or a compound key such as MyFunction.api.MyFunction.1:1.0.0)").option("--solution-folder <path>", "Path to the solution root folder (defaults to current directory)").examples(RESOURCE_REMOVE_EXAMPLES).trackedAction(processContext, async (resourceKey, options) => {
|
|
4913
5173
|
if (!resourceKey || resourceKey.trim().length === 0) {
|
|
4914
5174
|
OutputFormatter.error({
|
|
4915
5175
|
Result: RESULTS.Failure,
|
|
@@ -4919,11 +5179,11 @@ var registerResourceRemoveCommand = (resource) => {
|
|
|
4919
5179
|
processContext.exit(1);
|
|
4920
5180
|
return;
|
|
4921
5181
|
}
|
|
4922
|
-
if (!
|
|
5182
|
+
if (!RESOURCE_KEY_REGEX2.test(resourceKey)) {
|
|
4923
5183
|
OutputFormatter.error({
|
|
4924
5184
|
Result: RESULTS.Failure,
|
|
4925
|
-
Message: "<resource-key>
|
|
4926
|
-
Instructions: "Resource keys
|
|
5185
|
+
Message: "<resource-key> contains unsupported characters",
|
|
5186
|
+
Instructions: "Resource keys use letters, digits, and '. _ - :' only. Use 'uip solution resources list' to find a valid key."
|
|
4927
5187
|
});
|
|
4928
5188
|
processContext.exit(1);
|
|
4929
5189
|
return;
|
|
@@ -4959,6 +5219,7 @@ var registerResourceRemoveCommand = (resource) => {
|
|
|
4959
5219
|
processContext.exit(1);
|
|
4960
5220
|
return;
|
|
4961
5221
|
}
|
|
5222
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
4962
5223
|
const [builderError, builder] = await catchError(services.getSolutionBuilder(resolvedPath));
|
|
4963
5224
|
if (builderError) {
|
|
4964
5225
|
OutputFormatter.error({
|
|
@@ -5006,7 +5267,10 @@ var registerResourceRemoveCommand = (resource) => {
|
|
|
5006
5267
|
Data: captured
|
|
5007
5268
|
});
|
|
5008
5269
|
} finally {
|
|
5009
|
-
const
|
|
5270
|
+
const disposeError = await saveCasingNormalized(builder);
|
|
5271
|
+
if (!disposeError) {
|
|
5272
|
+
await normalizeResourceFileCasing(resolvedPath);
|
|
5273
|
+
}
|
|
5010
5274
|
if (disposeError) {
|
|
5011
5275
|
OutputFormatter.error({
|
|
5012
5276
|
Result: RESULTS.Failure,
|
|
@@ -5895,7 +6159,22 @@ var registerUploadCommand = (program) => {
|
|
|
5895
6159
|
uisPath = resolvedPath;
|
|
5896
6160
|
} else if (isDirectory || isUipxFile) {
|
|
5897
6161
|
const solutionDir = resolveSolutionDir(fs, resolvedPath);
|
|
5898
|
-
await
|
|
6162
|
+
const [prepareError] = await catchError(prepareSolutionResources(solutionDir, fs, {
|
|
6163
|
+
gate: true
|
|
6164
|
+
}));
|
|
6165
|
+
if (prepareError) {
|
|
6166
|
+
const errorCode = carriedErrorCode(prepareError) ?? (isUnpackableProjectTypeError(prepareError) ? "invalid_argument" : undefined);
|
|
6167
|
+
const contributionCode = prepareError.contributionCode;
|
|
6168
|
+
OutputFormatter.error({
|
|
6169
|
+
Result: RESULTS.Failure,
|
|
6170
|
+
Message: prepareError.message,
|
|
6171
|
+
...errorCode ? { ErrorCode: errorCode } : {},
|
|
6172
|
+
...typeof contributionCode === "string" ? { Context: { errorCode: contributionCode } } : {},
|
|
6173
|
+
Instructions: carriedInstructions(prepareError) ?? "Fix the reported problem in the project's files, then re-run the upload."
|
|
6174
|
+
});
|
|
6175
|
+
processContext.exit(1);
|
|
6176
|
+
return;
|
|
6177
|
+
}
|
|
5899
6178
|
tempDir = await fs.getTempDir();
|
|
5900
6179
|
const [bundleError, bundleResult] = await catchError(bundleSolution(fs, solutionDir, tempDir));
|
|
5901
6180
|
if (bundleError) {
|
|
@@ -6048,27 +6327,17 @@ function httpStatusOf(error) {
|
|
|
6048
6327
|
}
|
|
6049
6328
|
return;
|
|
6050
6329
|
}
|
|
6051
|
-
function probeAuthChallengeOf(error) {
|
|
6052
|
-
if (error instanceof Error && "authChallenge" in error) {
|
|
6053
|
-
const challenge = error.authChallenge;
|
|
6054
|
-
if (challenge && typeof challenge === "object") {
|
|
6055
|
-
return challenge;
|
|
6056
|
-
}
|
|
6057
|
-
}
|
|
6058
|
-
return {};
|
|
6059
|
-
}
|
|
6060
6330
|
function isSolutionNotFoundError(error) {
|
|
6061
6331
|
return httpStatusOf(error) === 404;
|
|
6062
6332
|
}
|
|
6063
6333
|
async function buildProbeFailureOutput(probeError, solutionId, identity) {
|
|
6064
6334
|
const status = httpStatusOf(probeError);
|
|
6065
6335
|
const isAuthRefusal = status === 401 || status === 403;
|
|
6066
|
-
const challenge = probeAuthChallengeOf(probeError);
|
|
6067
6336
|
const message = isAuthRefusal ? probeError.message : await extractErrorMessage(probeError);
|
|
6068
6337
|
const output = {
|
|
6069
6338
|
Result: RESULTS.Failure,
|
|
6070
6339
|
Message: `Failed to check whether solution ${solutionId} exists on Studio Web: ${message}`,
|
|
6071
|
-
Instructions: isAuthRefusal ? probeAuthInstructions(solutionId, identity
|
|
6340
|
+
Instructions: isAuthRefusal ? probeAuthInstructions(solutionId, identity) : "Verify your login (uip login) and tenant access, then retry. If the problem persists, contact your UiPath administrator."
|
|
6072
6341
|
};
|
|
6073
6342
|
if (status !== undefined) {
|
|
6074
6343
|
output.Context = {
|
|
@@ -6077,19 +6346,14 @@ async function buildProbeFailureOutput(probeError, solutionId, identity) {
|
|
|
6077
6346
|
method: "GET"
|
|
6078
6347
|
};
|
|
6079
6348
|
}
|
|
6080
|
-
if (status === 401 && identity?.type === "Application"
|
|
6349
|
+
if (status === 401 && identity?.type === "Application") {
|
|
6081
6350
|
output.ErrorCode = "permission_denied";
|
|
6082
6351
|
}
|
|
6083
6352
|
return output;
|
|
6084
6353
|
}
|
|
6085
|
-
function probeAuthInstructions(solutionId, identity
|
|
6086
|
-
const quoted = challenge.description ? ` ("${challenge.description}")` : "";
|
|
6087
|
-
if (challenge.error === "invalid_token") {
|
|
6088
|
-
return `Studio Web rejected the credential itself with the reason ` + `\`invalid_token\`${quoted} while checking whether solution ` + `${solutionId} exists. That is the platform refusing this token ` + `rather than the grants behind it, so unlike a grants refusal this ` + `one is worth a fresh 'uip login' — or, in a pipeline, a newly ` + `minted client-credentials token. Check too that the token was ` + `issued for the organization and tenant being called. Nothing was ` + `uploaded.`;
|
|
6089
|
-
}
|
|
6354
|
+
function probeAuthInstructions(solutionId, identity) {
|
|
6090
6355
|
const actor = identity?.type === "Application" ? `This session acts as external application ${identity.clientId ?? "(client id unknown)"}: it needs a Studio Web grant that can read a solution.` : identity?.type === "User" ? "This session acts as a user: check that your account has Studio Web access in this tenant." : "Check that this session may read a solution in Studio Web — an external application needs a StudioWebS2S grant, a user needs Studio Web access in the tenant.";
|
|
6091
|
-
|
|
6092
|
-
return `Studio Web refused the read, and the session is authenticated, so ` + `re-running 'uip login' mints the same token and fails the same way. ` + `${reported}${actor} Also confirm solution ${solutionId} lives in the organization ` + `and tenant this session logged into. Nothing was uploaded.`;
|
|
6356
|
+
return `Studio Web refused the read, and the session is authenticated, so ` + `re-running 'uip login' mints the same token and fails the same way. ` + `${actor} Also confirm solution ${solutionId} lives in the organization ` + `and tenant this session logged into. Nothing was uploaded.`;
|
|
6093
6357
|
}
|
|
6094
6358
|
function outputError(message) {
|
|
6095
6359
|
OutputFormatter.error({
|
|
@@ -6122,7 +6386,7 @@ var registerCommands = async (program) => {
|
|
|
6122
6386
|
registerResourceCommand(program);
|
|
6123
6387
|
registerDeleteCommand(program);
|
|
6124
6388
|
if (isPreviewBuild()) {
|
|
6125
|
-
const { registerListCommand } = await import("./list-
|
|
6389
|
+
const { registerListCommand } = await import("./list-dadxggxt.js");
|
|
6126
6390
|
registerListCommand(program);
|
|
6127
6391
|
}
|
|
6128
6392
|
registerFeedsCommand(program);
|
|
@@ -6130,4 +6394,4 @@ var registerCommands = async (program) => {
|
|
|
6130
6394
|
|
|
6131
6395
|
export { metadata, registerCommands };
|
|
6132
6396
|
|
|
6133
|
-
//# debugId=
|
|
6397
|
+
//# debugId=5681A456DD88C8F164756E2164756E21
|