Skip to content

Commit

Permalink
Merge pull request #1508 from contentstack/feat/DX-1058
Browse files Browse the repository at this point in the history
feat: enabled azure support in launch plugin
  • Loading branch information
aman19K authored Aug 12, 2024
2 parents accb8a7 + 1613c18 commit a79e36f
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 77 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/contentstack-launch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-launch
$ csdx COMMAND
running command...
$ csdx (--version|-v)
@contentstack/cli-launch/1.1.0 darwin-arm64 node-v22.2.0
@contentstack/cli-launch/1.2.0 darwin-arm64 node-v22.2.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack-launch/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/cli-launch",
"version": "1.1.0",
"version": "1.2.0",
"description": "Launch related operations",
"author": "Contentstack CLI",
"bin": {
Expand Down
87 changes: 70 additions & 17 deletions packages/contentstack-launch/src/adapters/file-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import find from 'lodash/find';
import FormData from 'form-data';
import filter from 'lodash/filter';
import includes from 'lodash/includes';
import isEmpty from 'lodash/isEmpty';
import { basename, resolve } from 'path';
import { cliux, configHandler, ux } from '@contentstack/cli-utilities';
import { cliux, configHandler, HttpClient, ux } from '@contentstack/cli-utilities';
import { createReadStream, existsSync, PathLike, statSync } from 'fs';

import { print } from '../util';
Expand Down Expand Up @@ -263,28 +264,80 @@ export default class FileUpload extends BaseClass {
* @memberof FileUpload
*/
async uploadFile(fileName: string, filePath: PathLike): Promise<void> {
const { uploadUrl, fields } = this.signedUploadUrlData;
const { uploadUrl, fields, headers } = this.signedUploadUrlData;
const formData = new FormData();

for (const { formFieldKey, formFieldValue } of fields) {
formData.append(formFieldKey, formFieldValue);
if (!isEmpty(fields)) {
for (const { formFieldKey, formFieldValue } of fields) {
formData.append(formFieldKey, formFieldValue);
}

formData.append('file', createReadStream(filePath), fileName);
await this.submitFormData(formData, uploadUrl);
} else if (!isEmpty(headers)) {
await this.uploadWithHttpClient(filePath, uploadUrl, headers, fileName);
}
}

formData.append('file', createReadStream(filePath) as any, fileName);
private async submitFormData(formData: FormData, uploadUrl: string): Promise<void> {
ux.action.start('Starting file upload...');
try {
await new Promise<void>((resolve, reject) => {
formData.submit(uploadUrl, (error, res) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});

await new Promise<void>((resolve) => {
ux.action.start('Starting file upload...');
formData.submit(uploadUrl, (error, res) => {
if (error) {
ux.action.stop('File upload failed!');
this.log('File upload failed. Please try again.', 'error');
this.log(error, 'error');
this.exit(1);
}
ux.action.stop();
} catch (error) {
ux.action.stop('File upload failed!');
this.log('File upload failed. Please try again.', 'error');
if (error instanceof Error) {
this.log(error.message, 'error');
}
this.exit(1);
}
}

private async uploadWithHttpClient(
filePath: PathLike,
uploadUrl: string,
headers: Array<{ key: string; value: string }>,
fileName: string,
): Promise<void> {
ux.action.start('Starting file upload...');
const httpClient = new HttpClient();
const form = new FormData();
form.append('file', createReadStream(filePath), fileName);

resolve();
// Convert headers array to a headers object
const headerObject = headers.reduce((acc, { key, value }) => {
acc[key] = value;
return acc;
}, {} as Record<string, string>);

try {
const response = await httpClient.headers(headerObject).put(uploadUrl, form);
const { status } = response;

if (status >= 200 && status < 300) {
ux.action.stop();
});
});
} else {
ux.action.stop('File upload failed!');
this.log('File upload failed. Please try again.', 'error');
this.exit(1);
}
} catch (error) {
ux.action.stop('File upload failed!');
this.log('File upload failed. Please try again.', 'error');
if (error instanceof Error) {
this.log(`Error: ${error.message}`, 'error');
}
this.exit(1);
}
}
}
4 changes: 2 additions & 2 deletions packages/contentstack-launch/src/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from '@contentstack/cli-utilities';

import config from './config';
import { GraphqlApiClient, Logger } from './util';
import { getLaunchHubUrl, GraphqlApiClient, Logger } from './util';
import { ConfigType, LogFn, Providers } from './types';

export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>;
Expand Down Expand Up @@ -105,7 +105,7 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
this.flags['data-dir'] || this.flags.config
? this.flags.config || resolve(this.flags['data-dir'], config.configName)
: resolve(process.cwd(), config.configName);
const baseUrl = config.launchBaseUrl || (config.launchHubUrls as Record<string, string>)[this.cmaAPIUrl];
const baseUrl = config.launchBaseUrl || getLaunchHubUrl();
this.sharedConfig = {
...require('./config').default,
currentConfig: {},
Expand Down
10 changes: 2 additions & 8 deletions packages/contentstack-launch/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@ const config = {
GITPROVIDER: 'GitHub',
FILEUPLOAD: 'FileUpload',
},
launchHubUrls: {
// NOTE CMA url used as launch url mapper to avoid conflict if user used any custom name
'https://api.contentstack.io': 'https://launch-api.contentstack.com',
'https://eu-api.contentstack.com': '',
'https://azure-na-api.contentstack.com': '',
'https://azure-eu-api.contentstack.com': '',
},
launchHubUrls: '',
launchBaseUrl: '',
supportedAdapters: ['GitHub'],
deploymentStatus: ['LIVE', 'FAILED', 'SKIPPED', 'DEPLOYED'],
Expand All @@ -45,7 +39,7 @@ const config = {
'Manually add custom variables to the list',
'Import variables from the local env file',
],
variableType: ''
variableType: '',
};

export default config;
4 changes: 4 additions & 0 deletions packages/contentstack-launch/src/graphql/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const createSignedUploadUrlMutation: DocumentNode = gql`
formFieldKey
formFieldValue
}
headers{
key
value
}
}
}
`;
Expand Down
20 changes: 19 additions & 1 deletion packages/contentstack-launch/src/util/common-utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,22 @@ async function selectProject(options: {
}
}

export { getOrganizations, selectOrg, selectProject };
function getLaunchHubUrl(): string {
const { cma } = configHandler.get('region') || {};
if (!cma) {
throw new Error('Region not configured. Please set the region with command $ csdx config:set:region');
}

let launchHubBaseUrl = cma.replace('api', 'launch-api');

if (launchHubBaseUrl.startsWith('http')) {
launchHubBaseUrl = launchHubBaseUrl.split('//')[1];
}

launchHubBaseUrl = launchHubBaseUrl.startsWith('dev11') ? launchHubBaseUrl.replace('dev11', 'dev') : launchHubBaseUrl;
launchHubBaseUrl = launchHubBaseUrl.endsWith('io') ? launchHubBaseUrl.replace('io', 'com') : launchHubBaseUrl;

return `https://${launchHubBaseUrl}`;
}

export { getOrganizations, selectOrg, selectProject, getLaunchHubUrl };
73 changes: 33 additions & 40 deletions packages/contentstack-launch/src/util/logs-polling-utilities.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import EventEmitter from "events";
import { ux } from "@contentstack/cli-utilities";
import { ApolloClient, ObservableQuery } from "@apollo/client/core";
import EventEmitter from 'events';
import { ux } from '@contentstack/cli-utilities';
import { ApolloClient, ObservableQuery } from '@apollo/client/core';

import { LogPollingInput, ConfigType } from "../types";
import {
deploymentQuery,
deploymentLogsQuery,
serverlessLogsQuery,
} from "../graphql";
import { LogPollingInput, ConfigType } from '../types';
import { deploymentQuery, deploymentLogsQuery, serverlessLogsQuery } from '../graphql';

export default class LogPolling {
private config: ConfigType;
Expand Down Expand Up @@ -69,15 +65,15 @@ export default class LogPolling {
let statusWatchQuery = this.getDeploymentStatus();
statusWatchQuery.subscribe(({ data, errors, error }) => {
if (error) {
this.$event.emit("deployment-logs", {
this.$event.emit('deployment-logs', {
message: error?.message,
msgType: "error",
msgType: 'error',
});
}
if (errors?.length && data === null) {
this.$event.emit("deployment-logs", {
this.$event.emit('deployment-logs', {
message: errors,
msgType: "error",
msgType: 'error',
});
statusWatchQuery.stopPolling();
}
Expand Down Expand Up @@ -110,46 +106,45 @@ export default class LogPolling {
{
deploymentUid: string | undefined;
}
>
>,
): void {
let timestamp: number = 0;
logsWatchQuery.subscribe(({ data, errors, error }) => {
ux.action.start("Loading deployment logs...");
ux.action.start('Loading deployment logs...');

if (error) {
ux.action.stop();
this.$event.emit("deployment-logs", {
this.$event.emit('deployment-logs', {
message: error?.message,
msgType: "error",
msgType: 'error',
});
this.$event.emit("deployment-logs", {
message: "DONE",
msgType: "debug",
this.$event.emit('deployment-logs', {
message: 'DONE',
msgType: 'debug',
});
logsWatchQuery.stopPolling();
}
if (errors?.length && data === null) {
ux.action.stop();
this.$event.emit("deployment-logs", {
this.$event.emit('deployment-logs', {
message: errors,
msgType: "error",
msgType: 'error',
});
this.$event.emit("deployment-logs", {
message: "DONE",
msgType: "debug",
this.$event.emit('deployment-logs', {
message: 'DONE',
msgType: 'debug',
});
logsWatchQuery.stopPolling();
}
if (this.deploymentStatus) {
let logsData = data?.getLogs;
if (logsData?.length) {
ux.action.stop();
this.$event.emit("deployment-logs", {
this.$event.emit('deployment-logs', {
message: logsData,
msgType: "info",
msgType: 'info',
});
timestamp =
new Date(logsData[logsData.length - 1].timestamp).getTime() + 1;
timestamp = new Date(logsData[logsData.length - 1].timestamp).getTime() + 1;
logsWatchQuery.setVariables({
deploymentUid: this.config.deployment,
timestamp: new Date(timestamp).toISOString(),
Expand All @@ -158,9 +153,9 @@ export default class LogPolling {

if (this.config.deploymentStatus.includes(this.deploymentStatus)) {
logsWatchQuery.stopPolling();
this.$event.emit("deployment-logs", {
message: "DONE",
msgType: "debug",
this.$event.emit('deployment-logs', {
message: 'DONE',
msgType: 'debug',
});
}
}
Expand Down Expand Up @@ -208,27 +203,26 @@ export default class LogPolling {
endTime: number;
};
}
>
>,
): void {
serverLogsWatchQuery.subscribe(({ data, errors, error }) => {
ux.action.start("Loading server logs...");
ux.action.start('Loading server logs...');
if (error) {
ux.action.stop();
this.$event.emit("server-logs", { message: error?.message, msgType: "error" });
this.$event.emit('server-logs', { message: error?.message, msgType: 'error' });
}
if (errors?.length && data === null) {
ux.action.stop();
this.$event.emit("server-logs", { message: errors, msgType: "error" });
this.$event.emit('server-logs', { message: errors, msgType: 'error' });
serverLogsWatchQuery.stopPolling();
}

let logsData = data?.getServerlessLogs?.logs;
let logsLength = logsData?.length;
if (logsLength > 0) {
ux.action.stop();
this.$event.emit("server-logs", { message: logsData, msgType: "info" });
this.startTime =
new Date(logsData[logsLength - 1].timestamp).getTime() + 1;
this.$event.emit('server-logs', { message: logsData, msgType: 'info' });
this.startTime = new Date(logsData[logsLength - 1].timestamp).getTime() + 1;
this.endTime = this.startTime + 10 * 1000;
} else if (logsLength === 0) {
this.endTime = this.endTime + 10 * 1000;
Expand All @@ -243,4 +237,3 @@ export default class LogPolling {
});
}
}

2 changes: 1 addition & 1 deletion packages/contentstack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $ npm install -g @contentstack/cli
$ csdx COMMAND
running command...
$ csdx (--version|-v)
@contentstack/cli/1.22.0 darwin-arm64 node-v22.2.0
@contentstack/cli/1.23.0 darwin-arm64 node-v22.2.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
Expand Down
Loading

0 comments on commit a79e36f

Please sign in to comment.