Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 94 additions & 42 deletions src/adapters/file-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import { print } from '../util';
import BaseClass from './base-class';
import { getFileList } from '../util/fs';
import { createSignedUploadUrlMutation, importProjectMutation } from '../graphql';
import { SignedUploadUrlData, FileUploadMethod } from '../types/launch';
import config from '../config';

export default class FileUpload extends BaseClass {
private signedUploadUrlData!: Record<string, any>;

/**
* @method run
*
Expand All @@ -26,28 +26,9 @@ export default class FileUpload extends BaseClass {
*/
async run(): Promise<void> {
if (this.config.isExistingProject) {
await this.initApolloClient();
const uploadLastFile =
this.config['redeploy-last-upload'] ||
(await cliux.inquire({
type: 'confirm',
default: false,
name: 'uploadLastFile',
message: 'Redeploy with last file upload?',
}));
if (!uploadLastFile) {
await this.createSignedUploadUrl();
const { zipName, zipPath } = await this.archive();
await this.uploadFile(zipName, zipPath);
}

const { uploadUid } = this.signedUploadUrlData || {
uploadUid: undefined,
};
await this.createNewDeployment(true, uploadUid);
await this.handleExistingProject();
} else {
await this.prepareForNewProjectCreation();
await this.createNewProject();
await this.handleNewProject();
}

this.prepareLaunchConfig();
Expand All @@ -56,13 +37,79 @@ export default class FileUpload extends BaseClass {
this.showSuggestion();
}

private async handleExistingProject(): Promise<void> {
await this.initApolloClient();

let redeployLatest = this.config['redeploy-latest'];
let redeployLastUpload = this.config['redeploy-last-upload'];

if (!redeployLatest && !redeployLastUpload) {
await this.confirmRedeployment();
const latestRedeploymentConfirmed = await this.confirmLatestRedeployment();
redeployLatest = latestRedeploymentConfirmed;
redeployLastUpload = !latestRedeploymentConfirmed;
}

if (redeployLastUpload && redeployLatest) {
this.log('redeploy-last-upload and redeploy-latest flags are not supported together.', 'error');
this.exit(1);
}

let uploadUid;
if (redeployLatest) {
const signedUploadUrlData = await this.createSignedUploadUrl();
uploadUid = signedUploadUrlData.uploadUid;
const { zipName, zipPath } = await this.archive();
await this.uploadFile(zipName, zipPath, signedUploadUrlData);
}

await this.createNewDeployment(true, uploadUid);
}

private async confirmRedeployment(): Promise<void> {
const redeploy = await cliux.inquire({
type: 'confirm',
name: 'deployLatestCommit',
message: 'Do you want to redeploy this existing Launch project?',
});
if (!redeploy) {
this.log('Project redeployment aborted.', 'info');
this.exit(1);
}
}

private async confirmLatestRedeployment(): Promise<boolean | void> {
const choices = [
...map(config.supportedFileUploadMethods, (fileUploadMethod) => ({
value: fileUploadMethod,
name: `Redeploy with ${fileUploadMethod}`,
}))
];

const selectedFileUploadMethod: FileUploadMethod = await cliux.inquire({
choices: choices,
type: 'search-list',
name: 'fileUploadMethod',
message: 'Choose a redeploy method to proceed',
});
if (selectedFileUploadMethod === FileUploadMethod.LastFileUpload) {
return false;
}
return true;
}

private async handleNewProject(): Promise<void> {
const uploadUid = await this.prepareAndUploadNewProjectFile();
await this.createNewProject(uploadUid);
}

/**
* @method createNewProject - Create new launch project
*
* @return {*} {Promise<void>}
* @memberof FileUpload
*/
async createNewProject(): Promise<void> {
async createNewProject(uploadUid: string): Promise<void> {
const { framework, projectName, buildCommand, outputDirectory, environmentName, serverCommand } = this.config;
await this.apolloClient
.mutate({
Expand All @@ -71,7 +118,7 @@ export default class FileUpload extends BaseClass {
project: {
projectType: 'FILEUPLOAD',
name: projectName,
fileUpload: { uploadUid: this.signedUploadUrlData.uploadUid },
fileUpload: { uploadUid },
environment: {
frameworkPreset: framework,
outputDirectory: outputDirectory,
Expand All @@ -95,7 +142,7 @@ export default class FileUpload extends BaseClass {
const canRetry = await this.handleNewProjectCreationError(error);

if (canRetry) {
return this.createNewProject();
return this.createNewProject(uploadUid);
}
});
}
Expand All @@ -106,7 +153,7 @@ export default class FileUpload extends BaseClass {
* @return {*} {Promise<void>}
* @memberof FileUpload
*/
async prepareForNewProjectCreation(): Promise<void> {
async prepareAndUploadNewProjectFile(): Promise<string> {
const {
name,
framework,
Expand All @@ -123,9 +170,9 @@ export default class FileUpload extends BaseClass {
this.config.deliveryToken = token;
// this.fileValidation();
await this.selectOrg();
await this.createSignedUploadUrl();
const signedUploadUrlData = await this.createSignedUploadUrl();
const { zipName, zipPath, projectName } = await this.archive();
await this.uploadFile(zipName, zipPath);
await this.uploadFile(zipName, zipPath, signedUploadUrlData);
this.config.projectName =
name ||
(await cliux.inquire({
Expand Down Expand Up @@ -186,6 +233,7 @@ export default class FileUpload extends BaseClass {
this.config.variableType = variableType as unknown as string;
this.config.envVariables = envVariables;
await this.handleEnvImportFlow();
return signedUploadUrlData.uploadUid;
}

/**
Expand Down Expand Up @@ -251,19 +299,23 @@ export default class FileUpload extends BaseClass {
/**
* @method createSignedUploadUrl - create pre signed url for file upload
*
* @return {*} {Promise<void>}
* @return {*} {Promise<SignedUploadUrlData>}
* @memberof FileUpload
*/
async createSignedUploadUrl(): Promise<void> {
this.signedUploadUrlData = await this.apolloClient
.mutate({ mutation: createSignedUploadUrlMutation })
.then(({ data: { signedUploadUrl } }) => signedUploadUrl)
.catch((error) => {
this.log('Something went wrong. Please try again.', 'warn');
this.log(error, 'error');
this.exit(1);
});
this.config.uploadUid = this.signedUploadUrlData.uploadUid;
async createSignedUploadUrl(): Promise<SignedUploadUrlData> {
try {
const result = await this.apolloClient.mutate({ mutation: createSignedUploadUrlMutation });
const signedUploadUrlData = result.data.signedUploadUrl;
this.config.uploadUid = signedUploadUrlData.uploadUid;
return signedUploadUrlData;
} catch (error) {
this.log('Something went wrong. Please try again.', 'warn');
if (error instanceof Error) {
this.log(error.message, 'error');
}
this.exit(1);
return {} as SignedUploadUrlData;
}
}

/**
Expand All @@ -274,8 +326,8 @@ export default class FileUpload extends BaseClass {
* @return {*} {Promise<void>}
* @memberof FileUpload
*/
async uploadFile(fileName: string, filePath: PathLike): Promise<void> {
const { uploadUrl, fields, headers, method } = this.signedUploadUrlData;
async uploadFile(fileName: string, filePath: PathLike, signedUploadUrlData: SignedUploadUrlData): Promise<void> {
const { uploadUrl, fields, headers, method } = signedUploadUrlData;
const formData = new FormData();

if (!isEmpty(fields)) {
Expand Down
62 changes: 46 additions & 16 deletions src/adapters/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,10 @@ export default class GitHub extends BaseClass {
* @memberof GitHub
*/
async run(): Promise<void> {
// NOTE New project creation Flow
if (this.config.isExistingProject) {
await this.initApolloClient();
await this.createNewDeployment();
await this.handleExistingProject();
} else {
// NOTE Existing project flow
// NOTE Step 1: Check is Github connected
if (await this.checkGitHubConnected()) {
// NOTE Step 2: check is the git remote available in the user's repo list
if (await this.checkGitRemoteAvailableAndValid()) {
if (await this.checkUserGitHubAccess()) {
// NOTE Step 3: check is the user has proper git access
await this.prepareForNewProjectCreation();
}
}
}

await this.createNewProject();
await this.handleNewProject();
}

this.prepareLaunchConfig();
Expand All @@ -47,6 +33,50 @@ export default class GitHub extends BaseClass {
this.showSuggestion();
}

private async handleExistingProject(): Promise<void> {
await this.initApolloClient();

const redeployLastUpload = this.config['redeploy-last-upload'];
const redeployLatest = this.config['redeploy-latest'];

if (redeployLastUpload) {
this.log('redeploy-last-upload flag is not supported for Github Project.', 'error');
this.exit(1);
}

if(!redeployLatest && !redeployLastUpload){
await this.confirmLatestRedeployment();
}

await this.createNewDeployment();
}

private async confirmLatestRedeployment(): Promise<void> {
const deployLatestCommit = await ux.inquire({
type: 'confirm',
name: 'deployLatestCommit',
message: 'Redeploy latest commit?',
});
if (!deployLatestCommit) {
this.log('Cannot create a new project because its an existing project.', 'info');
this.exit(1);
}
}

private async handleNewProject(): Promise<void> {
// NOTE Step 1: Check is Github connected
if (await this.checkGitHubConnected()) {
// NOTE Step 2: check is the git remote available in the user's repo list
if (await this.checkGitRemoteAvailableAndValid()) {
if (await this.checkUserGitHubAccess()) {
// NOTE Step 3: check is the user has proper git access
await this.prepareForNewProjectCreation();
}
}
}
await this.createNewProject();
}

/**
* @method createNewProject - Create new launch project
*
Expand Down
10 changes: 0 additions & 10 deletions src/adapters/pre-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,6 @@ export default class PreCheck extends BaseClass {
this.log('Existing launch project identified', 'info');

await this.displayPreDeploymentDetails();
const deployLatestCode =
this.config['redeploy-latest'] ||
(await ux.inquire({
type: 'confirm',
name: 'deployLatestSource',
message: 'Redeploy latest commit/code?',
}));
if (!deployLatestCode) {
this.exit(1);
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ const config = {
'Import variables from the local env file',
],
variableType: '',
supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX']
supportedFrameworksForServerCommands: ['ANGULAR', 'OTHER', 'REMIX'],
supportedFileUploadMethods: ['last file upload', 'new file']

};

export default config;
20 changes: 20 additions & 0 deletions src/types/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { LoggerType } from './utils';

type Providers = 'GitHub' | 'FileUpload';

enum FileUploadMethod {
LastFileUpload = 'last file upload',
NewFile = 'new file',
}

type LogFn = (message: string | any, logType?: LoggerType | PrintOptions | undefined) => void;

type ExitFn = (code?: number | undefined) => void;
Expand Down Expand Up @@ -38,6 +43,7 @@ type ConfigType = {
deployment?: string;
environment?: string;
provider?: Providers;
fileUploadMethod?: FileUploadMethod;
authorization?: string;
logsApiBaseUrl: string;
projectBasePath: string;
Expand All @@ -64,6 +70,18 @@ type GraphqlApiClientInput = {
headers?: GraphqlHeaders;
};

type FormField = {
formFieldKey: string;
formFieldValue: string;
};
type SignedUploadUrlData = {
uploadUrl: string;
fields: FormField[];
headers: { key: string; value: string }[];
method: string;
uploadUid: string;
};

export {
LogFn,
ExitFn,
Expand All @@ -73,4 +91,6 @@ export {
AdapterConstructorInputs,
GraphqlHeaders,
GraphqlApiClientInput,
SignedUploadUrlData,
FileUploadMethod,
};
Loading