@trayai/tray-sync-cli 1.0.14 → 1.0.15

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.
@@ -1,6 +1,42 @@
1
1
  export async function rollbackProject(client, projectId, versionNumber) {
2
2
  await client.request("POST", `/v1/projects/${projectId}/rollbacks/versions/${versionNumber}`);
3
3
  }
4
+ export async function getLatestProjectVersion(client, targetProjectId) {
5
+ const result = (await client.request("GET", `/v1/projects/${targetProjectId}/versions?last=1`));
6
+ const latest = result.elements?.[0];
7
+ if (!latest)
8
+ return null;
9
+ const [major, minor] = latest.versionNumber.split(".").map(Number);
10
+ return { major, minor };
11
+ }
12
+ export function computeNextVersionNumber(current, mode) {
13
+ if (!current)
14
+ return "1.0";
15
+ if (mode === "major")
16
+ return `${current.major + 1}.0`;
17
+ return `${current.major}.${current.minor + 1}`;
18
+ }
19
+ export async function createProjectVersion(client, targetProjectId, versionNumber, title, description) {
20
+ const result = (await client.request("POST", `/v1/projects/${targetProjectId}/versions/${versionNumber}`, { title, description }));
21
+ return {
22
+ versionNumber: result.versionNumber,
23
+ title: result.title,
24
+ description: result.description,
25
+ created: result.created,
26
+ };
27
+ }
28
+ export async function updateProjectVersion(client, projectId, versionNumber, fields) {
29
+ const result = (await client.request("PUT", `/v1/projects/${projectId}/versions/${versionNumber}`, fields));
30
+ return {
31
+ versionNumber: result.versionNumber,
32
+ title: result.title,
33
+ description: result.description,
34
+ created: result.created,
35
+ };
36
+ }
37
+ export async function deleteProjectVersion(client, projectId, versionNumber) {
38
+ await client.request("DELETE", `/v1/projects/${projectId}/versions/${versionNumber}`);
39
+ }
4
40
  export async function listProjectVersions(client, projectId, options = {}) {
5
41
  const params = new URLSearchParams();
6
42
  if (options.last !== undefined)
@@ -1,11 +1,14 @@
1
+ import ansis from "ansis";
1
2
  import { Command, InvalidArgumentError } from "commander";
2
- import { listProjectVersions, rollbackProject } from "../../api/resources/project.js";
3
+ import { computeNextVersionNumber, createProjectVersion, deleteProjectVersion, getLatestProjectVersion, listProjectVersions, rollbackProject, updateProjectVersion, } from "../../api/resources/project.js";
3
4
  import { isUuid } from "../../lib/uuid.js";
4
5
  import { parseVersionNumber } from "../../lib/versionNumber.js";
5
6
  import { OutputFormats } from "../../lib/outputFormat.js";
6
- import { printProjectRollbackResult, printProjectVersionListTable } from "../../views/api/project.v2.js";
7
+ import { printProjectRollbackResult, printProjectVersionDeletedResult, printProjectVersionListTable, printProjectVersionResult, } from "../../views/api/project.v2.js";
7
8
  import { printConfirmationJson } from "../../views/api/shared.js";
9
+ import { FAILURE_ICON } from "../../views/icons.js";
8
10
  import { addCommonApiOptions, apiClientFor, realDeps, runApiAction, } from "./shared.js";
11
+ const DEFAULT_VERSION_CREATE_TITLE = "Created via tray-sync-cli";
9
12
  const DEFAULT_VERSION_LIST_LIMIT = 5;
10
13
  function parseLimit(value) {
11
14
  const limit = Number(value);
@@ -48,6 +51,63 @@ export async function runProjectVersionList(deps, options) {
48
51
  }
49
52
  return 0;
50
53
  }
54
+ function printMutuallyExclusiveMajorAndVersion(stderr) {
55
+ stderr(`${FAILURE_ICON} ${ansis.bold("--major")} and ${ansis.bold("--version-number")} are mutually exclusive.`);
56
+ }
57
+ export async function runProjectVersionCreate(deps, options) {
58
+ if (options.major && options.versionNumber) {
59
+ printMutuallyExclusiveMajorAndVersion(deps.stderr);
60
+ return 1;
61
+ }
62
+ const client = await apiClientFor(deps, options);
63
+ const mode = options.major ? "major" : "minor";
64
+ const versionNumber = options.versionNumber ?? computeNextVersionNumber(await getLatestProjectVersion(client, options.projectId), mode);
65
+ const title = options.title ?? DEFAULT_VERSION_CREATE_TITLE;
66
+ const description = options.description ?? "";
67
+ const created = await createProjectVersion(client, options.projectId, versionNumber, title, description);
68
+ if (options.format === OutputFormats.JSON) {
69
+ printConfirmationJson(deps.stdout, { projectId: options.projectId, ...created });
70
+ }
71
+ else {
72
+ printProjectVersionResult(deps.stdout, options.projectId, created, "created");
73
+ }
74
+ return 0;
75
+ }
76
+ export async function runProjectVersionEdit(deps, options) {
77
+ if (options.title === undefined && options.description === undefined) {
78
+ deps.stderr(`${FAILURE_ICON} Nothing to edit — pass --title and/or --description.`);
79
+ return 1;
80
+ }
81
+ const client = await apiClientFor(deps, options);
82
+ const fields = {};
83
+ if (options.title !== undefined)
84
+ fields.title = options.title;
85
+ if (options.description !== undefined)
86
+ fields.description = options.description;
87
+ const updated = await updateProjectVersion(client, options.projectId, options.versionNumber, fields);
88
+ if (options.format === OutputFormats.JSON) {
89
+ printConfirmationJson(deps.stdout, { projectId: options.projectId, ...updated });
90
+ }
91
+ else {
92
+ printProjectVersionResult(deps.stdout, options.projectId, updated, "updated");
93
+ }
94
+ return 0;
95
+ }
96
+ export async function runProjectVersionDelete(deps, options) {
97
+ const client = await apiClientFor(deps, options);
98
+ await deleteProjectVersion(client, options.projectId, options.versionNumber);
99
+ if (options.format === OutputFormats.JSON) {
100
+ printConfirmationJson(deps.stdout, {
101
+ projectId: options.projectId,
102
+ versionNumber: options.versionNumber,
103
+ deleted: true,
104
+ });
105
+ }
106
+ else {
107
+ printProjectVersionDeletedResult(deps.stdout, options.projectId, options.versionNumber);
108
+ }
109
+ return 0;
110
+ }
51
111
  export const projectCommand = new Command("project").description("Manage projects");
52
112
  const versionCommand = new Command("version").description("Manage project versions");
53
113
  projectCommand.addCommand(versionCommand);
@@ -79,4 +139,56 @@ addCommonApiOptions(versionCommand
79
139
  format: opts.format,
80
140
  }));
81
141
  });
142
+ addCommonApiOptions(versionCommand
143
+ .command("create")
144
+ .description("Create a new version for a project")
145
+ .argument("<project-id>", "Tray project UUID", parseProjectId)
146
+ .option("--major", "bump the major version instead of minor")
147
+ .option("--version-number <major.minor>", "explicit target version number (overrides --major)", parseVersionNumber)
148
+ .option("--title <title>", `title for the created version (default "${DEFAULT_VERSION_CREATE_TITLE}")`)
149
+ .option("--description <description>", "description for the created version")).action(async (projectId, opts) => {
150
+ const deps = realDeps();
151
+ await runApiAction(deps, () => runProjectVersionCreate(deps, {
152
+ projectId,
153
+ major: opts.major,
154
+ versionNumber: opts.versionNumber,
155
+ title: opts.title,
156
+ description: opts.description,
157
+ region: opts.region,
158
+ token: opts.token,
159
+ format: opts.format,
160
+ }));
161
+ });
162
+ addCommonApiOptions(versionCommand
163
+ .command("edit")
164
+ .description("Edit a version's title and/or description")
165
+ .argument("<project-id>", "Tray project UUID", parseProjectId)
166
+ .requiredOption("--version-number <major.minor>", "target version number", parseVersionNumber)
167
+ .option("--title <title>", "new title")
168
+ .option("--description <description>", "new description")).action(async (projectId, opts) => {
169
+ const deps = realDeps();
170
+ await runApiAction(deps, () => runProjectVersionEdit(deps, {
171
+ projectId,
172
+ versionNumber: opts.versionNumber,
173
+ title: opts.title,
174
+ description: opts.description,
175
+ region: opts.region,
176
+ token: opts.token,
177
+ format: opts.format,
178
+ }));
179
+ });
180
+ addCommonApiOptions(versionCommand
181
+ .command("delete")
182
+ .description("Delete a version")
183
+ .argument("<project-id>", "Tray project UUID", parseProjectId)
184
+ .requiredOption("--version-number <major.minor>", "target version number", parseVersionNumber)).action(async (projectId, opts) => {
185
+ const deps = realDeps();
186
+ await runApiAction(deps, () => runProjectVersionDelete(deps, {
187
+ projectId,
188
+ versionNumber: opts.versionNumber,
189
+ region: opts.region,
190
+ token: opts.token,
191
+ format: opts.format,
192
+ }));
193
+ });
82
194
  //# sourceMappingURL=project.js.map
@@ -13,7 +13,8 @@ import { resolveContainedSafe } from "../lib/pathContainment.js";
13
13
  import { entityDisplayName } from "../lib/exportStructure.js";
14
14
  import { importProject, previewImport } from "../lib/promoteExecute.js";
15
15
  import { summarizeImpactForVersionDescription, toProjectImportImpact, } from "../lib/promoteReport.js";
16
- import { computeNextVersionNumber, createProjectVersion, getLatestProjectVersion, isFullyResolved, resolveProjectRequirements, scaffoldUnresolvedAuthentications, } from "../lib/promoteTarget.js";
16
+ import { isFullyResolved, resolveProjectRequirements, scaffoldUnresolvedAuthentications, } from "../lib/promoteTarget.js";
17
+ import { computeNextVersionNumber, createProjectVersion, getLatestProjectVersion, } from "../api/resources/project.js";
17
18
  import { resolveToken } from "../lib/tokenResolution.js";
18
19
  import { isUuid } from "../lib/uuid.js";
19
20
  import { OutputFormats, parseFormat } from "../lib/outputFormat.js";
@@ -96,30 +96,6 @@ export function validateAuthenticationMappings(mapping) {
96
96
  .filter(([, authenticationId]) => !isUuid(authenticationId))
97
97
  .map(([authExportId, value]) => ({ authExportId, value }));
98
98
  }
99
- export async function getLatestProjectVersion(client, targetProjectId) {
100
- const result = (await client.request("GET", `/v1/projects/${targetProjectId}/versions?last=1`));
101
- const latest = result.elements?.[0];
102
- if (!latest)
103
- return null;
104
- const [major, minor] = latest.versionNumber.split(".").map(Number);
105
- return { major, minor };
106
- }
107
- export function computeNextVersionNumber(current, mode) {
108
- if (!current)
109
- return "1.0";
110
- if (mode === "major")
111
- return `${current.major + 1}.0`;
112
- return `${current.major}.${current.minor + 1}`;
113
- }
114
- export async function createProjectVersion(client, targetProjectId, versionNumber, title, description) {
115
- const result = (await client.request("POST", `/v1/projects/${targetProjectId}/versions/${versionNumber}`, { title, description }));
116
- return {
117
- versionNumber: result.versionNumber,
118
- title: result.title,
119
- description: result.description,
120
- created: result.created,
121
- };
122
- }
123
99
  export async function resolveProjectRequirements(client, deps, options) {
124
100
  const targetResolution = await resolveTargetProjectId(client, {
125
101
  projectDirPath: options.projectDirPath,
@@ -21,4 +21,10 @@ export function printProjectVersionListTable(stdout, versions) {
21
21
  }
22
22
  stdout(table.toString());
23
23
  }
24
+ export function printProjectVersionResult(stdout, projectId, version, verb) {
25
+ stdout(`${SUCCESS_ICON} Project ${ansis.bold(projectId)} version ${ansis.bold(version.versionNumber)} ${verb}: ${ansis.bold(version.title)}.`);
26
+ }
27
+ export function printProjectVersionDeletedResult(stdout, projectId, versionNumber) {
28
+ stdout(`${SUCCESS_ICON} Project ${ansis.bold(projectId)} version ${ansis.bold(versionNumber)} deleted.`);
29
+ }
24
30
  //# sourceMappingURL=project.v2.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayai/tray-sync-cli",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "CLI tool to clone Tray projects and related assets to a local directory, and promote them between Tray environments",
5
5
  "bin": {
6
6
  "tray": "dist/cli.js"