@contrail/cli 3.1.7 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
17
17
  $ contrail COMMAND
18
18
  running command...
19
19
  $ contrail (--version)
20
- @contrail/cli/3.1.7 darwin-arm64 node-v20.18.0
20
+ @contrail/cli/3.2.0 darwin-arm64 node-v20.18.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -10,7 +10,7 @@ const app_extension_packages_1 = require("../../../api/app-extension-packages");
10
10
  const apps_1 = require("../../../api/apps");
11
11
  const login_1 = require("../../../auth/login");
12
12
  const basecommand_1 = require("../../../basecommand");
13
- const extension_package_1 = require("../../../helpers/app/extension-package");
13
+ const extension_package_deployer_1 = require("../../../helpers/app/extension-package-deployer");
14
14
  const load_app_config_1 = require("../../../helpers/app/load-app-config");
15
15
  const interfaces_1 = require("../../../interfaces");
16
16
  const logger_1 = tslib_1.__importDefault(require("../../../logger"));
@@ -40,7 +40,7 @@ class DeployExtension extends basecommand_1.BaseCommand {
40
40
  await this.validateExtensionDeclaration(appDeclaration, extensionIdentifier);
41
41
  const extensionDir = this.getExtensionDirectory(extensionIdentifier);
42
42
  // 2. Package and upload extension
43
- const createdPackage = await (0, extension_package_1.createExtensionPackage)(app.id, extensionDir, { debug: this.flags.debug });
43
+ const createdPackage = await (0, extension_package_deployer_1.createExtensionPackage)(app.id, extensionDir, { debug: this.flags.debug });
44
44
  // 3. Poll until package is ready (timeout after 1 minute)
45
45
  const readyPackage = await this.pollUntilPackageIsReady(createdPackage);
46
46
  logger_1.default.info("Extension package is ready...Checking for extension deployment");
@@ -6,7 +6,7 @@ const core_1 = require("@oclif/core");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const login_1 = require("../../../../auth/login");
8
8
  const basecommand_1 = require("../../../../basecommand");
9
- const extension_package_1 = require("../../../../helpers/app/extension-package");
9
+ const extension_package_deployer_1 = require("../../../../helpers/app/extension-package-deployer");
10
10
  const load_app_config_1 = require("../../../../helpers/app/load-app-config");
11
11
  const logger_1 = tslib_1.__importDefault(require("../../../../logger"));
12
12
  const lodash_1 = require("lodash");
@@ -26,7 +26,7 @@ class ListExtensionDeployments extends basecommand_1.BaseCommand {
26
26
  await (0, login_1.authUser)();
27
27
  logger_1.default.info(`${chalk_1.default.blue.bold('START')} Listing extension deployments.`);
28
28
  const appDeclaration = (0, load_app_config_1.loadAppConfig)();
29
- const app = await (0, extension_package_1.getExistingApp)(appDeclaration);
29
+ const app = await (0, extension_package_deployer_1.getExistingApp)(appDeclaration);
30
30
  const packages = this.flags.all
31
31
  ? await this.getAllExtensionPackages(app.id)
32
32
  : await this.getLatest20ExtensionPackages(app.id);
@@ -14,6 +14,7 @@ const logger_1 = tslib_1.__importDefault(require("../../logger"));
14
14
  const child_process_1 = tslib_1.__importDefault(require("child_process"));
15
15
  const fs_1 = tslib_1.__importDefault(require("fs"));
16
16
  const extensions_deployer_1 = require("./extensions-deployer");
17
+ const metadata_extractor_1 = require("./metadata-extractor");
17
18
  class AppDeployer {
18
19
  debug;
19
20
  dryRun;
@@ -165,6 +166,25 @@ class AppDeployer {
165
166
  }
166
167
  }
167
168
  exports.AppDeployer = AppDeployer;
169
+ async function createSourceArchive(tmpDir) {
170
+ logger_1.default.info('Creating source code archive...');
171
+ const sourceFiles = ['src/', 'package.json', 'app.yml'];
172
+ if (fs_1.default.existsSync('package-lock.json')) {
173
+ sourceFiles.push('package-lock.json');
174
+ }
175
+ const sourceDir = `${tmpDir}/source`;
176
+ fs_1.default.mkdirSync(sourceDir, { recursive: true });
177
+ sourceFiles.forEach((sourceFile) => {
178
+ if (!fs_1.default.existsSync(sourceFile))
179
+ return;
180
+ const isDirectory = fs_1.default.statSync(sourceFile).isDirectory();
181
+ const copyOptions = isDirectory ? { recursive: true } : undefined;
182
+ fs_1.default.cpSync(sourceFile, `${sourceDir}/${sourceFile}`, copyOptions);
183
+ });
184
+ await (0, zip_a_folder_1.zip)(`${sourceDir}/`, `${tmpDir}/source-code.zip`);
185
+ logger_1.default.info('Source code archive created.');
186
+ return `${tmpDir}/source-code.zip`;
187
+ }
168
188
  async function createNodePackage(appIdentifier, debug, dryRun) {
169
189
  // zip src code and package.json and package-lock.json files into a zip file
170
190
  // and upload as a code package.
@@ -178,6 +198,8 @@ async function createNodePackage(appIdentifier, debug, dryRun) {
178
198
  fs_1.default.cpSync('package-lock.json', 'tmp/package-lock.json');
179
199
  }
180
200
  fs_1.default.mkdirSync('tmp/node_modules', { recursive: true });
201
+ const buildInfoPath = await (0, metadata_extractor_1.createBuildMetadata)('tmp');
202
+ const sourceArchivePath = await createSourceArchive('tmp');
181
203
  logger_1.default.info('Installing production dependencies started...');
182
204
  child_process_1.default.execSync('npm install --omit=dev --prefix tmp/');
183
205
  logger_1.default.info('Installing production dependencies done.');
@@ -199,6 +221,9 @@ async function createNodePackage(appIdentifier, debug, dryRun) {
199
221
  logger_1.default.info('Copying Assets done.');
200
222
  // including the app.yml file in the package at the dist level
201
223
  fs_1.default.cpSync('app.yml', 'tmp/dist/app.yml');
224
+ // Copy build info and source code zip to dist
225
+ fs_1.default.cpSync(buildInfoPath, 'tmp/dist/build-info.json');
226
+ fs_1.default.cpSync(sourceArchivePath, 'tmp/dist/source-code.zip');
202
227
  logger_1.default.info('Zipping package...');
203
228
  await (0, zip_a_folder_1.zip)('tmp/', 'tmp.zip');
204
229
  logger_1.default.info('Zipping package done.');
@@ -96,10 +96,7 @@ async function uploadExtensionPackage(appExtensionPackage, tmpDir, options) {
96
96
  });
97
97
  logger_1.default.debug(`${chalk_1.default.green.bold('EXTENSION')} Uploaded extension package to ${appExtensionPackage.uploadURL}`);
98
98
  logger_1.default.info(`${chalk_1.default.green.bold('EXTENSION')} Extension package uploaded. ID: ${appExtensionPackage.id}`);
99
- if (options.debug) {
100
- logger_1.default.debug(JSON.stringify(result, null, 2));
101
- }
102
- if (result.status !== 200) {
99
+ if (result.status < 200 || result.status >= 300) {
103
100
  logger_1.default.error(`${chalk_1.default.red.bold('EXTENSION')} Failed to upload extension package. Status: ${result.status}`);
104
101
  logger_1.default.error(JSON.stringify(result, null, 2));
105
102
  throw new Error(`Failed to upload extension package. Status: ${result.status}`);
@@ -0,0 +1 @@
1
+ export declare function createBuildMetadata(tmpDir: string): string;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuildMetadata = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const os = tslib_1.__importStar(require("os"));
6
+ const child_process_1 = require("child_process");
7
+ const fs_1 = tslib_1.__importDefault(require("fs"));
8
+ function createBuildMetadata(tmpDir) {
9
+ const buildTimestamp = new Date();
10
+ const systemInfo = {
11
+ nodeVersion: process.version,
12
+ platform: process.platform,
13
+ architecture: process.arch,
14
+ operatingSystem: os.type(),
15
+ osRelease: os.release(),
16
+ hostname: os.hostname(),
17
+ totalMemory: os.totalmem(),
18
+ freeMemory: os.freemem(),
19
+ cpuCount: os.cpus().length,
20
+ cpuModel: os.cpus()[0]?.model || 'unknown',
21
+ homeDirectory: os.homedir(),
22
+ tmpDirectory: os.tmpdir(),
23
+ processId: process.pid,
24
+ processTitle: process.title,
25
+ execPath: process.execPath,
26
+ workingDirectory: process.cwd(),
27
+ };
28
+ const environmentInfo = {
29
+ shell: process.env.SHELL,
30
+ term: process.env.TERM,
31
+ lang: process.env.LANG,
32
+ timezone: process.env.TZ || Intl.DateTimeFormat().resolvedOptions().timeZone,
33
+ };
34
+ let gitInfo = {};
35
+ try {
36
+ const gitCommitHash = (0, child_process_1.execSync)('git rev-parse HEAD', {
37
+ encoding: 'utf8',
38
+ timeout: 5000,
39
+ }).trim();
40
+ const gitBranch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
41
+ encoding: 'utf8',
42
+ timeout: 5000,
43
+ }).trim();
44
+ const gitRemoteUrl = (0, child_process_1.execSync)('git config --get remote.origin.url', {
45
+ encoding: 'utf8',
46
+ timeout: 5000,
47
+ }).trim();
48
+ const gitCommitMessage = (0, child_process_1.execSync)('git log -1 --pretty=%B', {
49
+ encoding: 'utf8',
50
+ timeout: 5000,
51
+ }).trim();
52
+ const gitAuthor = (0, child_process_1.execSync)('git log -1 --pretty=format:"%an <%ae>"', {
53
+ encoding: 'utf8',
54
+ timeout: 5000,
55
+ }).trim();
56
+ const gitCommitDate = (0, child_process_1.execSync)('git log -1 --pretty=format:"%ai"', {
57
+ encoding: 'utf8',
58
+ timeout: 5000,
59
+ }).trim();
60
+ const gitTagsOutput = (0, child_process_1.execSync)('git tag --points-at HEAD', {
61
+ encoding: 'utf8',
62
+ timeout: 5000,
63
+ }).trim();
64
+ const gitTags = gitTagsOutput ? gitTagsOutput.split('\n') : [];
65
+ gitInfo = {
66
+ commitHash: gitCommitHash,
67
+ shortCommitHash: gitCommitHash.substring(0, 8),
68
+ branch: gitBranch,
69
+ remoteUrl: gitRemoteUrl,
70
+ commitMessage: gitCommitMessage,
71
+ author: gitAuthor,
72
+ commitDate: gitCommitDate,
73
+ tags: gitTags,
74
+ };
75
+ }
76
+ catch (error) {
77
+ gitInfo = {
78
+ error: 'Git information unavailable',
79
+ message: error instanceof Error ? error.message : 'Unknown git error',
80
+ };
81
+ }
82
+ const buildInfo = {
83
+ buildTimestamp: buildTimestamp.toISOString(),
84
+ buildTimestampUnix: Math.floor(buildTimestamp.getTime() / 1000),
85
+ buildTool: 'contrail-cli',
86
+ buildUser: process.env.USER || process.env.USERNAME || 'unknown',
87
+ system: systemInfo,
88
+ environment: environmentInfo,
89
+ git: gitInfo,
90
+ metadata: {
91
+ schemaVersion: '1.0.0',
92
+ generatedBy: 'contrail-cli-app-deployer',
93
+ purpose: 'Build and deployment metadata for debugging and auditing',
94
+ },
95
+ };
96
+ const buildInfoPath = `${tmpDir}/build-info.json`;
97
+ fs_1.default.writeFileSync(buildInfoPath, JSON.stringify(buildInfo, null, 2));
98
+ return buildInfoPath;
99
+ }
100
+ exports.createBuildMetadata = createBuildMetadata;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.1.7",
2
+ "version": "3.2.0",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.1.7",
3
+ "version": "3.2.0",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",