From 972c35232481f6e6462a53d64a62ad270e4c7956 Mon Sep 17 00:00:00 2001 From: "burak.yildirim" Date: Sat, 6 Apr 2024 15:58:20 +0300 Subject: [PATCH 1/6] add cli methods for publish --- package.json | 2 +- src/constant.ts | 2 + src/core/command-runner.ts | 159 +++++++++++++++++++++ src/core/commands.ts | 253 +++++++++++++++++++++++++++++++++ src/core/interactive-runner.ts | 52 ++++++- src/core/writer.ts | 38 +++++ src/services/index.ts | 123 ++++++++++++++++ 7 files changed, 623 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 811f6c2..665ad35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@appcircle/cli", - "version": "1.2.0-beta.3", + "version": "1.2.0-beta.3.1", "description": "CLI tool for running Appcircle services from the command line", "main": "bin/appcircle", "bin": { diff --git a/src/constant.ts b/src/constant.ts index ab49ab1..67f9a62 100644 --- a/src/constant.ts +++ b/src/constant.ts @@ -49,3 +49,5 @@ export const PROGRAM_NAME = "appcircle"; export const UNKNOWN_PARAM_VALUE = '-' export const CURRENT_PARAM_VALUE = 'current' +export let globalVariables : {[key:string]: string} = {} + diff --git a/src/core/command-runner.ts b/src/core/command-runner.ts index cbf0312..3c7afdc 100644 --- a/src/core/command-runner.ts +++ b/src/core/command-runner.ts @@ -54,6 +54,18 @@ import { getOrganizationUserinfo, assignRolesToUserInOrganitaion, getOrganizationUsersWithRoles, + createPublishProfile, + getPublishProfiles, + uploadAppVersion, + deleteAppVersion, + getAppVersionDownloadLink, + getPublishByAppVersion, + startExistingPublishFlow, + setAppVersionReleaseCandidateStatus, + switchPublishProfileAutoPublishSettings, + getPublishProfileDetailById, + getPublishVariableGroups, + getPublishVariableListByGroupId } from '../services'; import { commandWriter, configWriter } from './writer'; import { trustAppcircleCertificate } from '../security/trust-url-certificate'; @@ -201,6 +213,149 @@ const handleOrganizationCommand = async (command: ProgramCommand, params: any) = } }; +const handlePublishCommand = async (command: ProgramCommand, params: any) => { + if(command.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`){ + try{ + await createPublishProfile({platform: params.platform, name: params.name}); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-profileList`) { + try{ + const profiles = await getPublishProfiles({platform: params.platform}); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: profiles, + }); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionUpload`){ + const spinner = createOra('Try to upload the app version').start(); + try{ + const responseData = await uploadAppVersion(params); + commandWriter(CommandTypes.PUBLISH, responseData); + spinner.text = `App version uploaded successfully.\n\nTaskId: ${responseData.taskId}`; + spinner.succeed(); + }catch(e : any){ + spinner.fail('Upload failed'); + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionDelete`){ + const spinner = createOra('Try to remove the app version').start(); + try{ + const responseData = await deleteAppVersion(params); + commandWriter(CommandTypes.PUBLISH, responseData); + spinner.text = `App version removed successfully.\n\nTaskId: ${responseData.taskId}`; + spinner.succeed(); + }catch(e : any){ + spinner.fail('Remove failed'); + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-startExistingFlow`){ + const spinner = createOra('Publish flow starting').start(); + try{ + const publish = await getPublishByAppVersion(params); + const firstStep = publish.steps[0]; + const startResponse = await startExistingPublishFlow({...params, publishId: firstStep.publishId}) + commandWriter(CommandTypes.PUBLISH, startResponse); + spinner.text = `Publish started successfully.`; + spinner.succeed(); + }catch(e: any){ + spinner.fail('Process failed'); + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionDownload`){ + const spinner = createOra('Fetching app version download link').start(); + try{ + const responseData = await getAppVersionDownloadLink(params); + commandWriter(CommandTypes.PUBLISH, responseData); + spinner.text = `App version download link fetched successfully.\n\nDownload Link: ${responseData}`; + spinner.succeed(); + }catch(e : any){ + spinner.fail('Process failed'); + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-markAsReleaseCandidate`){ + try{ + await setAppVersionReleaseCandidateStatus(params); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-setAsAutoPublish`){ + try{ + const publishProfileDetails = await getPublishProfileDetailById(params); + await switchPublishProfileAutoPublishSettings({...params, currentProfileSettings: publishProfileDetails.profileSettings}); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`){ + try{ + const variableGroups = await getPublishVariableGroups(); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: variableGroups, + }); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`){ + try{ + const variables = await getPublishVariableListByGroupId(params); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: variables.variables, + }); + }catch(e : any){ + if(e?.response?.data?.message){ + console.error(e.response.data.message) + }else { + throw e; + } + } + } + else { + const beutufiyCommandName = command.fullCommandName.split('-').join(' '); + console.error(`"${beutufiyCommandName} ..." command not found \nRun "${beutufiyCommandName} --help" for more information`); + } +}; + export const runCommand = async (command: ProgramCommand) => { const params = command.opts() as any; const commandName = command.name(); @@ -222,6 +377,10 @@ export const runCommand = async (command: ProgramCommand) => { return handleOrganizationCommand(command, params); } + if(command.isGroupCommand(CommandTypes.PUBLISH)) { + return handlePublishCommand(command, params); + } + switch (commandName) { case CommandTypes.LOGIN: { responseData = await getToken(params); diff --git a/src/core/commands.ts b/src/core/commands.ts index cbef18b..e4fd3fb 100644 --- a/src/core/commands.ts +++ b/src/core/commands.ts @@ -13,6 +13,7 @@ export enum CommandTypes { CONFIG = 'config', LOGIN = 'login', ORGANIZATION = 'organization', + PUBLISH = 'publish', LIST_BUILD_PROFILES = 'listBuildProfiles', LIST_BUILD_PROFILE_BRANCHES = 'listBuildProfileBranches', LIST_BUILD_PROFILE_WORKFLOWS = 'listBuildProfileWorkflows', @@ -374,6 +375,258 @@ export const Commands: CommandType[] = [ ], params: [], }, + { + command: CommandTypes.PUBLISH, + description: 'Publish', + longDescription: 'Manage publish module actions.', + subCommands: [ + { + command: 'createProfile', + description: 'Create a publish profile', + longDescription: 'Create a new publish profile', + params: [{ + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'name', + description: 'Profile name', + type: CommandParameterTypes.STRING, + defaultValue: undefined, + valueType: 'string', + required: true, + } + ], + }, + { + command: 'profileList', + description: 'Publish profile list', + longDescription: 'Get list of publish profile', + params: [{ + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }], + }, + { + command: 'versionUpload', + description: 'Upload a new app version', + longDescription: 'Upload a new version to selected publish profile', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'app', + description: 'App path', + type: CommandParameterTypes.STRING, + valueType: 'path', + required: true + } + ], + }, + { + command: 'versionDelete', + description: 'Remove app version', + longDescription: 'Remove app version from selected publish profile', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + { + command: 'versionDownload', + description: 'Download app version', + longDescription: 'Download app version from selected publish profile', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + { + command: 'markAsReleaseCandidate', + description: 'Mark/Unmark as Release Candidate', + longDescription: 'Mark/Unmark an app version as Release Candidate', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'releaseCandidate', + description: 'Release Candidate', + type: CommandParameterTypes.BOOLEAN, + valueType: 'boolean', + required: true + } + ], + }, + { + command: 'startExistingFlow', + description: 'Start a publish', + longDescription: 'Starts a publish', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + { + command: 'setAsAutoPublish', + description: 'Set Publish Profile as Auto Publish', + longDescription: 'Start a publish process when a new version is received.', + params: [ + { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.STRING, + defaultValue: 'ios', + valueType: 'string', + required: true, + }, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'enableAutoPublish', + description: 'Enable Auto Publish', + type: CommandParameterTypes.BOOLEAN, + valueType: 'boolean', + required: true + } + ], + }, + { + command: 'publishVariables', + description: 'Publish Variables', + longDescription: 'Publish Variables', + params: [], + subCommands: [ + { + command: 'groups', + description: 'Groups', + longDescription: 'Get list of publish variable group', + params: [], + }, + { + command: 'variables', + description: 'Publish Variable List', + longDescription: 'View publish variables by group', + params: [ + { + name: 'publishVariableGroupId', + description: 'Variable Group ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + } + ] + } + ], + params: [], + }, { command: CommandTypes.LIST_BUILD_PROFILES, description: 'Get list of build profiles', diff --git a/src/core/interactive-runner.ts b/src/core/interactive-runner.ts index 35dd840..ce58f31 100644 --- a/src/core/interactive-runner.ts +++ b/src/core/interactive-runner.ts @@ -6,7 +6,7 @@ import moment from 'moment'; import { prompt, Select, AutoComplete, BooleanPrompt, MultiSelect } from 'enquirer'; import { runCommand } from './command-runner'; import { Commands, CommandParameterTypes, CommandTypes, CommandType } from './commands'; -import { APPCIRCLE_COLOR, UNKNOWN_PARAM_VALUE } from '../constant'; +import { APPCIRCLE_COLOR, OperatingSystems, UNKNOWN_PARAM_VALUE, globalVariables } from '../constant'; import { createOra } from '../utils/orahelper'; import { getBranches, @@ -25,6 +25,9 @@ import { getOrganizationInvitations, getOrganizationUsers, getOrganizationUserinfo, + getPublishProfiles, + getAppVersions, + getPublishVariableGroups, } from '../services'; import { DefaultEnvironmentVariables, getConfigStore } from '../config'; import { ProgramCommand, createCommandActionCallback } from '../program'; @@ -307,7 +310,39 @@ const handleInteractiveParamsOrArguments = async ( param.params = userList.map((user: any) => ({ name: user.id, message: user._message || ` ${user.id} (${user.email})` })); spinner.text = 'Users fetched'; spinner.succeed(); - } else if (param.name === 'email' && param.type === CommandParameterTypes.SELECT) { + }else if(param.name === 'publishProfileId' && param.type === CommandParameterTypes.SELECT){ + const spinner = ora('Publish Profiles Fetching').start(); + const selectedPlatform = globalVariables["platform"]; + const publishProfiles = await getPublishProfiles({ platform: selectedPlatform }); + param.params = publishProfiles.map((profile:any) => ({name:profile.id, message: ` ${profile.id} (${profile.name}) - ${(OperatingSystems as any)[profile.platformType]}`})); + spinner.text = 'Publish Profiles Fetched'; + spinner.succeed(); + }else if(param.name === 'appVersionId' && param.type === CommandParameterTypes.SELECT){ + const spinner = ora('App Versions Fetching').start(); + const selectedPlatform = globalVariables["platform"]; + const selectedPublishProfileId = globalVariables["publishProfileId"]; + const appVersions = await getAppVersions({ platform: selectedPlatform, publishProfileId: selectedPublishProfileId }); + if (!appVersions || appVersions.length === 0) { + spinner.text = 'No app versions available'; + spinner.fail(); + }else { + param.params = appVersions.map((appVersion:any) => ({name:appVersion.id, message: ` ${appVersion.id} - ${appVersion.name}(${appVersion.version}) ${appVersion.releaseCandidate ? '(Release Candidate)' : ''}`})); + spinner.text = 'App Versions Fetched'; + spinner.succeed(); + } + }else if(param.name === 'publishVariableGroupId' && param.type === CommandParameterTypes.SELECT){ + const spinner = ora('Publish Variable Groups Fetching').start(); + const groups = await getPublishVariableGroups(); + if (!groups || groups.length === 0) { + spinner.text = 'No groups available'; + spinner.fail(); + }else { + param.params = groups.map((group:any) => ({name:group.id, message: ` ${group.id} (${group.name})`})); + spinner.text = 'Publish Variable Groups Fetched'; + spinner.succeed(); + } + } + else if (param.name === 'email' && param.type === CommandParameterTypes.SELECT) { const spinner = ora('Invitations fetching').start(); const invitationsList = await getOrganizationInvitations({ organizationId: params.organizationId || params.currentOrganizationId || '' }); if (param.required !== false && (!invitationsList || invitationsList.length === 0)) { @@ -321,7 +356,7 @@ const handleInteractiveParamsOrArguments = async ( param.params = invitationsList.map((invitation: any) => ({ name: invitation.userEmail, message: invitation._message || invitation.userEmail })); spinner.text = 'Invitations fetched'; spinner.succeed(); - } else if (param.name === 'value' && params.isSecret) { + }else if (param.name === 'value' && params.isSecret) { param.type = CommandParameterTypes.PASSWORD; } @@ -346,6 +381,11 @@ const handleInteractiveParamsOrArguments = async ( }, ]); (params as any)[param.name] = (stringPrompt as any)[Object.keys(stringPrompt)[0]]; + + // set global variables from selected params + Object.keys(params).map((key:string) => { + globalVariables[key] = params[key]; + }); } else if (param.type === CommandParameterTypes.BOOLEAN) { const booleanPrompt = new BooleanPrompt({ name: param.name, @@ -365,6 +405,10 @@ const handleInteractiveParamsOrArguments = async ( ], }); (params as any)[param.name] = await selectPrompt.run(); + // set global variables from selected params + Object.keys(params).map((key:string) => { + globalVariables[key] = params[key]; + }); } else if (param.type === CommandParameterTypes.MULTIPLE_SELECT && param.params) { const selectPrompt = new AutoComplete({ name: param.name, @@ -387,7 +431,6 @@ const handleInteractiveParamsOrArguments = async ( const handleCommandParamsAndArguments = async (selectedCommand: CommandType, parentCommand: any): Promise => { const params = (await handleInteractiveParamsOrArguments(selectedCommand.params || [])) || {}; const args = (await handleInteractiveParamsOrArguments(selectedCommand.arguments || [])) || {}; - return createCommandActionCallback({ parent: parentCommand || null, name: () => selectedCommand.command, @@ -398,7 +441,6 @@ const handleCommandParamsAndArguments = async (selectedCommand: CommandType, par const handleSelectedCommand = async (command: CommandType, __parentCommand?: any): Promise => { const preparedCommand = await handleCommandParamsAndArguments(command, __parentCommand); - if (command.subCommands?.length) { const commandSelect = new AutoComplete({ name: 'action', diff --git a/src/core/writer.ts b/src/core/writer.ts index 455e538..c187ad7 100644 --- a/src/core/writer.ts +++ b/src/core/writer.ts @@ -288,6 +288,44 @@ const writersMap: { [key in CommandTypes]: (data: any) => void } = { console.log(data.data); } }, + [CommandTypes.PUBLISH]: (data: any) => { + if(data.fullCommandName === `${PROGRAM_NAME}-publish-profileList`){ + data.data.length > 0 ? + console.table( + data.data.map((publishProfile: any) => ({ + 'Profile Id': publishProfile.id, + 'Profile Name': publishProfile.name, + 'Last Upload Version': publishProfile.lastUploadVersion, + 'Last Upload Version Code': publishProfile.lastUploadVersionCode, + 'Version Code': publishProfile.version, + 'App Unique Id': publishProfile.appUniqueId , + 'Latest Publish': publishProfile.latestPublishDate ? moment(publishProfile.publishDate).calendar() : '-', + 'Target Platform': (OperatingSystems as any)[publishProfile.platformType], + Created: publishProfile.createDate ? moment(publishProfile.createDate).calendar() : '-', + Updated: publishProfile.updateDate ? moment(publishProfile.updateDate).calendar() : '-', + })) + ) : console.log(' No publish profile found'); + }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`){ + data.data.length > 0 ? console.table( + data.data.map((group: any) => ({ + 'Group Id': group.id, + 'Group Name': group.name, + Created: group.createDate ? moment(group.createDate).calendar() : '-', + Updated: group.updateDate ? moment(group.updateDate).calendar() : '-', + })) + ) : console.log(' No publish variable group found'); + }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`){ + data.data.length > 0 ? console.table( + data.data.map((variable: any) => ({ + 'Key Name': variable.key, + 'Key Value': variable.isSecret ? '********' : variable.value, + })) + ) : console.log(' No publish variable found'); + } + else { + console.log(data.data) + } + } }; export const commandWriter = (command: CommandTypes, data: any) => { diff --git a/src/services/index.ts b/src/services/index.ts index b21e9f1..ff877bb 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -36,6 +36,23 @@ export async function createDistributionProfile(options: OptionsType<{ name: str return response.data; } +export async function createPublishProfile(options: OptionsType<{ platform: string, name: string }>) { + const response = await appcircleApi.post( + `publish/v2/profiles/${options.platform}`, + { name: options.name }, + { headers: getHeaders() } + ); + return response.data; +} + +export async function getPublishProfiles(options: OptionsType<{ platform: string }>) { + const response = await appcircleApi.get( + `publish/v2/profiles/${options.platform}`, + { headers: getHeaders() } + ); + return response.data; +} + export async function getTestingGroups(options: OptionsType) { const response = await appcircleApi.get(`distribution/v2/testing-groups`, { headers: getHeaders(), @@ -166,6 +183,112 @@ export async function uploadArtifact(options: OptionsType<{ message: string; app return uploadResponse.data; } +export async function uploadAppVersion(options: OptionsType<{ app: string; publishProfileId: string, platform:string }>) { + const data = new FormData(); + data.append('File', fs.createReadStream(options.app)); + + const uploadResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, data, { + maxContentLength: Infinity, + maxBodyLength: Infinity, + headers: { + ...getHeaders(), + ...data.getHeaders(), + 'Content-Type': 'multipart/form-data;boundary=' + data.getBoundary(), + }, + }); + return uploadResponse.data; +} +export async function getAppVersions(options: OptionsType<{ publishProfileId: string, platform:string }>) { + const appVersions = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, { + headers: getHeaders(), + }); + return appVersions.data; +} +export async function getPublishByAppVersion(options: OptionsType<{ publishProfileId: string, platform:string,appVersionId: string }>) { + const publish = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}/publish`, { + headers: getHeaders(), + }); + return publish.data; +} +export async function deleteAppVersion(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { + const appVersions = await appcircleApi.delete(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}`, { + headers: getHeaders(), + }); + return appVersions.data; +} +export async function getAppVersionDownloadLink(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { + + const downloadResponse = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=download`, + { + headers: getHeaders() + } + ); + + return downloadResponse.data; +} +export async function getPublishProfileDetailById(options: OptionsType<{ publishProfileId: string, platform:string }>) { + + const response = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`, + { + headers: getHeaders() + } + ); + + return response.data; +} +export async function getPublishVariableGroups() { + + const response = await appcircleApi.get(`publish/v2/variable-groups`, + { + headers: getHeaders() + } + ); + + return response.data; +} +export async function getPublishVariableListByGroupId(options: OptionsType<{ publishVariableGroupId: string }>) { + + const response = await appcircleApi.get(`publish/v2/variable-groups/${options.publishVariableGroupId}`, + { + headers: getHeaders() + } + ); + + return response.data; +} +export async function setAppVersionReleaseCandidateStatus(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, releaseCandidate: boolean }>) { + + const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=releaseCandidate`,{ + ReleaseCandidate: options.releaseCandidate + }, + { + headers: getHeaders() + } + ); + + return response.data; +} + +export async function switchPublishProfileAutoPublishSettings(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, enableAutoPublish: boolean, currentProfileSettings: any }>) { + const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`,{ + profileSettings: {...options.currentProfileSettings , whenNewVersionRecieved: options.enableAutoPublish } + }, + { + headers: getHeaders() + } + ); + + return response.data; +} + +export async function startExistingPublishFlow(options: OptionsType<{ publishProfileId: string, platform:string, publishId: string }>) { + const startResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/publish/${options.publishId}?action=restart`,"{}", + { + headers: getHeaders() + } + ); + return startResponse.data; +} export async function getEnvironmentVariableGroups(options: OptionsType = {}) { const environmentVariableGroups = await appcircleApi.get(`build/v1/variable-groups`, { headers: getHeaders(), From 60b9ac0ca1afa4ce6426006d01517e3bad5b53c1 Mon Sep 17 00:00:00 2001 From: "burak.yildirim" Date: Sat, 6 Apr 2024 16:02:41 +0300 Subject: [PATCH 2/6] fix conflict --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 665ad35..811f6c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@appcircle/cli", - "version": "1.2.0-beta.3.1", + "version": "1.2.0-beta.3", "description": "CLI tool for running Appcircle services from the command line", "main": "bin/appcircle", "bin": { From df64376350440948c65c85ee88ab4539adec47b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Tu=C4=9Frul=20P=C4=B1nar?= Date: Sun, 7 Apr 2024 14:53:57 +0300 Subject: [PATCH 3/6] fix(commands): publish commands --- README.md | 1 + src/core/command-runner.ts | 172 ++++++++++----------------------- src/core/commands.ts | 82 ++++------------ src/core/interactive-runner.ts | 19 ++-- src/core/writer.ts | 19 ++-- src/main.ts | 7 +- src/services/index.ts | 122 +---------------------- src/services/publish.ts | 132 +++++++++++++++++++++++++ 8 files changed, 229 insertions(+), 325 deletions(-) create mode 100644 src/services/publish.ts diff --git a/README.md b/README.md index 468cc03..50151cd 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Below is the list of commands currently supported by Appcircle CLI: | `appcircle config [argument] [options]` | View and edit Appcircle CLI properties | | `appcircle login [--pat]` | Get an access token for the session | | `appcircle organization [action] [options]` | Manage organization users, roles, and details | + `appcircle publish [options]` | Manage publish module actions | | `appcircle listBuildProfiles` | Get the list of build profiles | | `appcircle listDistributionProfiles` | Get the list of distribution profiles | | `appcircle listBuildProfileWorkflows [--profileId]` | Get the list of workflows for the profile | diff --git a/src/core/command-runner.ts b/src/core/command-runner.ts index 3c7afdc..0a57ed4 100644 --- a/src/core/command-runner.ts +++ b/src/core/command-runner.ts @@ -65,7 +65,7 @@ import { switchPublishProfileAutoPublishSettings, getPublishProfileDetailById, getPublishVariableGroups, - getPublishVariableListByGroupId + getPublishVariableListByGroupId, } from '../services'; import { commandWriter, configWriter } from './writer'; import { trustAppcircleCertificate } from '../security/trust-url-certificate'; @@ -214,143 +214,77 @@ const handleOrganizationCommand = async (command: ProgramCommand, params: any) = }; const handlePublishCommand = async (command: ProgramCommand, params: any) => { - if(command.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`){ - try{ - await createPublishProfile({platform: params.platform, name: params.name}); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-profileList`) { - try{ - const profiles = await getPublishProfiles({platform: params.platform}); - commandWriter(CommandTypes.PUBLISH, { - fullCommandName: command.fullCommandName, - data: profiles, - }); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionUpload`){ + if (command.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`) { + const profileRes = await createPublishProfile({ platform: params.platform, name: params.name }); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: profileRes, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profileList`) { + const profiles = await getPublishProfiles({ platform: params.platform }); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: profiles, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionUpload`) { const spinner = createOra('Try to upload the app version').start(); - try{ + try { const responseData = await uploadAppVersion(params); commandWriter(CommandTypes.PUBLISH, responseData); spinner.text = `App version uploaded successfully.\n\nTaskId: ${responseData.taskId}`; spinner.succeed(); - }catch(e : any){ + } catch (e: any) { spinner.fail('Upload failed'); - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } + throw e; } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionDelete`){ + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionDelete`) { const spinner = createOra('Try to remove the app version').start(); - try{ + try { const responseData = await deleteAppVersion(params); commandWriter(CommandTypes.PUBLISH, responseData); spinner.text = `App version removed successfully.\n\nTaskId: ${responseData.taskId}`; spinner.succeed(); - }catch(e : any){ + } catch (e: any) { spinner.fail('Remove failed'); - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } + throw e; } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-startExistingFlow`){ + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-startExistingFlow`) { const spinner = createOra('Publish flow starting').start(); - try{ - const publish = await getPublishByAppVersion(params); - const firstStep = publish.steps[0]; - const startResponse = await startExistingPublishFlow({...params, publishId: firstStep.publishId}) - commandWriter(CommandTypes.PUBLISH, startResponse); - spinner.text = `Publish started successfully.`; - spinner.succeed(); - }catch(e: any){ - spinner.fail('Process failed'); - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-versionDownload`){ + const publish = await getPublishByAppVersion(params); + const firstStep = publish.steps[0]; + const startResponse = await startExistingPublishFlow({ ...params, publishId: firstStep.publishId }); + commandWriter(CommandTypes.PUBLISH, startResponse); + spinner.text = `Publish started successfully.`; + spinner.succeed(); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionDownload`) { const spinner = createOra('Fetching app version download link').start(); - try{ + try { const responseData = await getAppVersionDownloadLink(params); commandWriter(CommandTypes.PUBLISH, responseData); spinner.text = `App version download link fetched successfully.\n\nDownload Link: ${responseData}`; spinner.succeed(); - }catch(e : any){ + } catch (e: any) { spinner.fail('Process failed'); - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-markAsReleaseCandidate`){ - try{ - await setAppVersionReleaseCandidateStatus(params); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-setAsAutoPublish`){ - try{ - const publishProfileDetails = await getPublishProfileDetailById(params); - await switchPublishProfileAutoPublishSettings({...params, currentProfileSettings: publishProfileDetails.profileSettings}); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`){ - try{ - const variableGroups = await getPublishVariableGroups(); - commandWriter(CommandTypes.PUBLISH, { - fullCommandName: command.fullCommandName, - data: variableGroups, - }); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - }else if(command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`){ - try{ - const variables = await getPublishVariableListByGroupId(params); - commandWriter(CommandTypes.PUBLISH, { - fullCommandName: command.fullCommandName, - data: variables.variables, - }); - }catch(e : any){ - if(e?.response?.data?.message){ - console.error(e.response.data.message) - }else { - throw e; - } - } - } - else { + throw e; + } + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-markAsReleaseCandidate`) { + await setAppVersionReleaseCandidateStatus(params); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-setAsAutoPublish`) { + const publishProfileDetails = await getPublishProfileDetailById(params); + await switchPublishProfileAutoPublishSettings({ ...params, currentProfileSettings: publishProfileDetails.profileSettings }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`) { + const variableGroups = await getPublishVariableGroups(); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: variableGroups, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`) { + const variables = await getPublishVariableListByGroupId(params); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: variables.variables, + }); + } else { const beutufiyCommandName = command.fullCommandName.split('-').join(' '); console.error(`"${beutufiyCommandName} ..." command not found \nRun "${beutufiyCommandName} --help" for more information`); } @@ -364,7 +298,7 @@ export const runCommand = async (command: ProgramCommand) => { //console.log('Full-Command-Name: ', command.fullCommandName, params); //In interactive mode, if any parameters have errors, we can't continue execution. - if(params.isError){ + if (params.isError) { process.exit(1); } @@ -377,7 +311,7 @@ export const runCommand = async (command: ProgramCommand) => { return handleOrganizationCommand(command, params); } - if(command.isGroupCommand(CommandTypes.PUBLISH)) { + if (command.isGroupCommand(CommandTypes.PUBLISH)) { return handlePublishCommand(command, params); } diff --git a/src/core/commands.ts b/src/core/commands.ts index e4fd3fb..d96de3b 100644 --- a/src/core/commands.ts +++ b/src/core/commands.ts @@ -64,6 +64,16 @@ export type CommandType = { params: ParamType[]; }; +const platformParam = { + name: 'platform', + description: 'Platform (ios/android)', + type: CommandParameterTypes.SELECT, + params: [{ name: 'ios' , message: 'iOS' }, { name: 'android', message: 'Android' }], + defaultValue: 'ios', + valueType: 'string', + required: true, +}; + export const Commands: CommandType[] = [ { command: CommandTypes.CONFIG, @@ -384,14 +394,7 @@ export const Commands: CommandType[] = [ command: 'createProfile', description: 'Create a publish profile', longDescription: 'Create a new publish profile', - params: [{ - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + params: [platformParam, { name: 'name', description: 'Profile name', @@ -406,28 +409,14 @@ export const Commands: CommandType[] = [ command: 'profileList', description: 'Publish profile list', longDescription: 'Get list of publish profile', - params: [{ - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }], + params: [platformParam], }, { command: 'versionUpload', description: 'Upload a new app version', longDescription: 'Upload a new version to selected publish profile', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', @@ -449,14 +438,7 @@ export const Commands: CommandType[] = [ description: 'Remove app version', longDescription: 'Remove app version from selected publish profile', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', @@ -478,14 +460,7 @@ export const Commands: CommandType[] = [ description: 'Download app version', longDescription: 'Download app version from selected publish profile', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', @@ -507,14 +482,7 @@ export const Commands: CommandType[] = [ description: 'Mark/Unmark as Release Candidate', longDescription: 'Mark/Unmark an app version as Release Candidate', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', @@ -543,14 +511,7 @@ export const Commands: CommandType[] = [ description: 'Start a publish', longDescription: 'Starts a publish', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', @@ -572,14 +533,7 @@ export const Commands: CommandType[] = [ description: 'Set Publish Profile as Auto Publish', longDescription: 'Start a publish process when a new version is received.', params: [ - { - name: 'platform', - description: 'Platform (ios/android)', - type: CommandParameterTypes.STRING, - defaultValue: 'ios', - valueType: 'string', - required: true, - }, + platformParam, { name: 'publishProfileId', description: 'Publish Profile ID', diff --git a/src/core/interactive-runner.ts b/src/core/interactive-runner.ts index ce58f31..f0cd22a 100644 --- a/src/core/interactive-runner.ts +++ b/src/core/interactive-runner.ts @@ -6,7 +6,7 @@ import moment from 'moment'; import { prompt, Select, AutoComplete, BooleanPrompt, MultiSelect } from 'enquirer'; import { runCommand } from './command-runner'; import { Commands, CommandParameterTypes, CommandTypes, CommandType } from './commands'; -import { APPCIRCLE_COLOR, OperatingSystems, UNKNOWN_PARAM_VALUE, globalVariables } from '../constant'; +import { APPCIRCLE_COLOR, OperatingSystems, UNKNOWN_PARAM_VALUE } from '../constant'; import { createOra } from '../utils/orahelper'; import { getBranches, @@ -312,19 +312,20 @@ const handleInteractiveParamsOrArguments = async ( spinner.succeed(); }else if(param.name === 'publishProfileId' && param.type === CommandParameterTypes.SELECT){ const spinner = ora('Publish Profiles Fetching').start(); - const selectedPlatform = globalVariables["platform"]; + const selectedPlatform = params["platform"]; const publishProfiles = await getPublishProfiles({ platform: selectedPlatform }); param.params = publishProfiles.map((profile:any) => ({name:profile.id, message: ` ${profile.id} (${profile.name}) - ${(OperatingSystems as any)[profile.platformType]}`})); spinner.text = 'Publish Profiles Fetched'; spinner.succeed(); }else if(param.name === 'appVersionId' && param.type === CommandParameterTypes.SELECT){ const spinner = ora('App Versions Fetching').start(); - const selectedPlatform = globalVariables["platform"]; - const selectedPublishProfileId = globalVariables["publishProfileId"]; + const selectedPlatform = params["platform"]; + const selectedPublishProfileId = params["publishProfileId"]; const appVersions = await getAppVersions({ platform: selectedPlatform, publishProfileId: selectedPublishProfileId }); if (!appVersions || appVersions.length === 0) { spinner.text = 'No app versions available'; spinner.fail(); + return { isError: true }; }else { param.params = appVersions.map((appVersion:any) => ({name:appVersion.id, message: ` ${appVersion.id} - ${appVersion.name}(${appVersion.version}) ${appVersion.releaseCandidate ? '(Release Candidate)' : ''}`})); spinner.text = 'App Versions Fetched'; @@ -336,6 +337,7 @@ const handleInteractiveParamsOrArguments = async ( if (!groups || groups.length === 0) { spinner.text = 'No groups available'; spinner.fail(); + return { isError: true }; }else { param.params = groups.map((group:any) => ({name:group.id, message: ` ${group.id} (${group.name})`})); spinner.text = 'Publish Variable Groups Fetched'; @@ -382,10 +384,6 @@ const handleInteractiveParamsOrArguments = async ( ]); (params as any)[param.name] = (stringPrompt as any)[Object.keys(stringPrompt)[0]]; - // set global variables from selected params - Object.keys(params).map((key:string) => { - globalVariables[key] = params[key]; - }); } else if (param.type === CommandParameterTypes.BOOLEAN) { const booleanPrompt = new BooleanPrompt({ name: param.name, @@ -405,10 +403,7 @@ const handleInteractiveParamsOrArguments = async ( ], }); (params as any)[param.name] = await selectPrompt.run(); - // set global variables from selected params - Object.keys(params).map((key:string) => { - globalVariables[key] = params[key]; - }); + } else if (param.type === CommandParameterTypes.MULTIPLE_SELECT && param.params) { const selectPrompt = new AutoComplete({ name: param.name, diff --git a/src/core/writer.ts b/src/core/writer.ts index c187ad7..f35fd55 100644 --- a/src/core/writer.ts +++ b/src/core/writer.ts @@ -289,18 +289,25 @@ const writersMap: { [key in CommandTypes]: (data: any) => void } = { } }, [CommandTypes.PUBLISH]: (data: any) => { - if(data.fullCommandName === `${PROGRAM_NAME}-publish-profileList`){ + if(data.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`){ + console.table( + [{ 'Id:': data.data.id, + 'Name:': data.data.name, + 'Created:': data.data.createDate ? moment(data.data.createDate).calendar() : '-', + }] + ) + } else if(data.fullCommandName === `${PROGRAM_NAME}-publish-profileList`){ data.data.length > 0 ? console.table( data.data.map((publishProfile: any) => ({ - 'Profile Id': publishProfile.id, - 'Profile Name': publishProfile.name, - 'Last Upload Version': publishProfile.lastUploadVersion, - 'Last Upload Version Code': publishProfile.lastUploadVersionCode, + 'Id': publishProfile.id, + 'Name': publishProfile.name, + 'Last Version': publishProfile.lastUploadVersion, + 'Last Version Code': publishProfile.lastUploadVersionCode, 'Version Code': publishProfile.version, 'App Unique Id': publishProfile.appUniqueId , 'Latest Publish': publishProfile.latestPublishDate ? moment(publishProfile.publishDate).calendar() : '-', - 'Target Platform': (OperatingSystems as any)[publishProfile.platformType], + 'Platform': (OperatingSystems as any)[publishProfile.platformType], Created: publishProfile.createDate ? moment(publishProfile.createDate).calendar() : '-', Updated: publishProfile.updateDate ? moment(publishProfile.updateDate).calendar() : '-', })) diff --git a/src/main.ts b/src/main.ts index 831f559..23f7d7d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,9 +7,10 @@ import { getConsoleOutputType, setConsoleOutputType } from './config'; import { error } from 'console'; import { ProgramError } from './core/ProgramError'; import { PROGRAM_NAME } from './constant'; +import chalk from 'chalk'; const collectErrorMessageFromData = (data: any) => { - return data ? '\n↳ ' + Object.keys(data).map(key => data[key]).join('\n↳ '): ''; + return data ? '\n↳ ' + Object.keys(data).filter(k => k !== 'stackTrace').map(key => ' -' +key +': ' + data[key]).join('\n↳ '): ''; } const handleError = (error: any) => { @@ -22,9 +23,9 @@ const handleError = (error: any) => { } else { if (axios.isAxiosError(error)) { const data = error.response?.data as any; - console.error(`\n${error.message} ${error.response?.statusText}${collectErrorMessageFromData(data)}`); + console.error(`\n${chalk.red('✖')} ${error.message} ${chalk.red(error.response?.statusText)}${collectErrorMessageFromData(data)}`); if(error.response?.status === 401) { - console.error(`Run "${PROGRAM_NAME} login --help" command for more information.`); + console.error(`Run ${chalk.cyan(`"${PROGRAM_NAME} login --help"`)} command for more information.`); } } else if (error instanceof ProgramError) { console.error(error.message); diff --git a/src/services/index.ts b/src/services/index.ts index ff877bb..68ea2c3 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -36,21 +36,6 @@ export async function createDistributionProfile(options: OptionsType<{ name: str return response.data; } -export async function createPublishProfile(options: OptionsType<{ platform: string, name: string }>) { - const response = await appcircleApi.post( - `publish/v2/profiles/${options.platform}`, - { name: options.name }, - { headers: getHeaders() } - ); - return response.data; -} - -export async function getPublishProfiles(options: OptionsType<{ platform: string }>) { - const response = await appcircleApi.get( - `publish/v2/profiles/${options.platform}`, - { headers: getHeaders() } - ); - return response.data; } export async function getTestingGroups(options: OptionsType) { @@ -183,112 +168,6 @@ export async function uploadArtifact(options: OptionsType<{ message: string; app return uploadResponse.data; } -export async function uploadAppVersion(options: OptionsType<{ app: string; publishProfileId: string, platform:string }>) { - const data = new FormData(); - data.append('File', fs.createReadStream(options.app)); - - const uploadResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, data, { - maxContentLength: Infinity, - maxBodyLength: Infinity, - headers: { - ...getHeaders(), - ...data.getHeaders(), - 'Content-Type': 'multipart/form-data;boundary=' + data.getBoundary(), - }, - }); - return uploadResponse.data; -} -export async function getAppVersions(options: OptionsType<{ publishProfileId: string, platform:string }>) { - const appVersions = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, { - headers: getHeaders(), - }); - return appVersions.data; -} -export async function getPublishByAppVersion(options: OptionsType<{ publishProfileId: string, platform:string,appVersionId: string }>) { - const publish = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}/publish`, { - headers: getHeaders(), - }); - return publish.data; -} -export async function deleteAppVersion(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { - const appVersions = await appcircleApi.delete(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}`, { - headers: getHeaders(), - }); - return appVersions.data; -} -export async function getAppVersionDownloadLink(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { - - const downloadResponse = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=download`, - { - headers: getHeaders() - } - ); - - return downloadResponse.data; -} -export async function getPublishProfileDetailById(options: OptionsType<{ publishProfileId: string, platform:string }>) { - - const response = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`, - { - headers: getHeaders() - } - ); - - return response.data; -} -export async function getPublishVariableGroups() { - - const response = await appcircleApi.get(`publish/v2/variable-groups`, - { - headers: getHeaders() - } - ); - - return response.data; -} -export async function getPublishVariableListByGroupId(options: OptionsType<{ publishVariableGroupId: string }>) { - - const response = await appcircleApi.get(`publish/v2/variable-groups/${options.publishVariableGroupId}`, - { - headers: getHeaders() - } - ); - - return response.data; -} -export async function setAppVersionReleaseCandidateStatus(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, releaseCandidate: boolean }>) { - - const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=releaseCandidate`,{ - ReleaseCandidate: options.releaseCandidate - }, - { - headers: getHeaders() - } - ); - - return response.data; -} - -export async function switchPublishProfileAutoPublishSettings(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, enableAutoPublish: boolean, currentProfileSettings: any }>) { - const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`,{ - profileSettings: {...options.currentProfileSettings , whenNewVersionRecieved: options.enableAutoPublish } - }, - { - headers: getHeaders() - } - ); - - return response.data; -} - -export async function startExistingPublishFlow(options: OptionsType<{ publishProfileId: string, platform:string, publishId: string }>) { - const startResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/publish/${options.publishId}?action=restart`,"{}", - { - headers: getHeaders() - } - ); - return startResponse.data; -} export async function getEnvironmentVariableGroups(options: OptionsType = {}) { const environmentVariableGroups = await appcircleApi.get(`build/v1/variable-groups`, { headers: getHeaders(), @@ -518,3 +397,4 @@ export const getUserInfo = async () => { }; export * from './organization'; +export * from './publish'; diff --git a/src/services/publish.ts b/src/services/publish.ts new file mode 100644 index 0000000..0485666 --- /dev/null +++ b/src/services/publish.ts @@ -0,0 +1,132 @@ + +import fs from 'fs'; +import FormData from 'form-data'; +import { ProgramError } from '../core/ProgramError'; +import { OptionsType, appcircleApi, getHeaders } from './api'; + +export async function createPublishProfile(options: OptionsType<{ platform: string, name: string }>) { + const response = await appcircleApi.post( + `publish/v2/profiles/${options.platform}`, + { name: options.name }, + { headers: getHeaders() } + ); + return response.data; + } + + export async function getPublishProfiles(options: OptionsType<{ platform: string }>) { + const response = await appcircleApi.get( + `publish/v2/profiles/${options.platform}`, + { headers: getHeaders() } + ); + return response.data; + } + + export async function startExistingPublishFlow(options: OptionsType<{ publishProfileId: string, platform:string, publishId: string }>) { + const startResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/publish/${options.publishId}?action=restart`,"{}", + { + headers: getHeaders() + } + ); + return startResponse.data; + } + + export async function getPublishVariableGroups() { + + const response = await appcircleApi.get(`publish/v2/variable-groups`, + { + headers: getHeaders() + } + ); + + return response.data; + } + export async function getPublishVariableListByGroupId(options: OptionsType<{ publishVariableGroupId: string }>) { + + const response = await appcircleApi.get(`publish/v2/variable-groups/${options.publishVariableGroupId}`, + { + headers: getHeaders() + } + ); + + return response.data; + } + export async function setAppVersionReleaseCandidateStatus(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, releaseCandidate: boolean }>) { + + const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=releaseCandidate`,{ + ReleaseCandidate: options.releaseCandidate + }, + { + headers: getHeaders() + } + ); + + return response.data; + } + + export async function switchPublishProfileAutoPublishSettings(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, enableAutoPublish: boolean, currentProfileSettings: any }>) { + const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`,{ + profileSettings: {...options.currentProfileSettings , whenNewVersionRecieved: options.enableAutoPublish } + }, + { + headers: getHeaders() + } + ); + + return response.data; + } + + export async function uploadAppVersion(options: OptionsType<{ app: string; publishProfileId: string, platform:string }>) { + const data = new FormData(); + data.append('File', fs.createReadStream(options.app)); + + const uploadResponse = await appcircleApi.post(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, data, { + maxContentLength: Infinity, + maxBodyLength: Infinity, + headers: { + ...getHeaders(), + ...data.getHeaders(), + 'Content-Type': 'multipart/form-data;boundary=' + data.getBoundary(), + }, + }); + return uploadResponse.data; + } + export async function getAppVersions(options: OptionsType<{ publishProfileId: string, platform:string }>) { + const appVersions = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions`, { + headers: getHeaders(), + }); + return appVersions.data; + } + export async function getPublishByAppVersion(options: OptionsType<{ publishProfileId: string, platform:string,appVersionId: string }>) { + const publish = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}/publish`, { + headers: getHeaders(), + }); + return publish.data; + } + export async function deleteAppVersion(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { + const appVersions = await appcircleApi.delete(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}`, { + headers: getHeaders(), + }); + return appVersions.data; + } + export async function getAppVersionDownloadLink(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string }>) { + + const downloadResponse = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}/app-versions/${options.appVersionId}?action=download`, + { + headers: getHeaders() + } + ); + + return downloadResponse.data; + } + export async function getPublishProfileDetailById(options: OptionsType<{ publishProfileId: string, platform:string }>) { + + const response = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`, + { + headers: getHeaders() + } + ); + + return response.data; + } + + \ No newline at end of file From 87af9e34af58b9ae7c44730a7f3bf812de578288 Mon Sep 17 00:00:00 2001 From: "burak.yildirim" Date: Sun, 7 Apr 2024 17:11:16 +0300 Subject: [PATCH 4/6] fix/review fix --- src/core/command-runner.ts | 72 +++++-- src/core/commands.ts | 390 +++++++++++++++++++++++-------------- src/core/writer.ts | 38 +++- src/services/index.ts | 2 - src/services/publish.ts | 48 ++++- 5 files changed, 380 insertions(+), 170 deletions(-) diff --git a/src/core/command-runner.ts b/src/core/command-runner.ts index 0a57ed4..0c916b9 100644 --- a/src/core/command-runner.ts +++ b/src/core/command-runner.ts @@ -66,6 +66,10 @@ import { getPublishProfileDetailById, getPublishVariableGroups, getPublishVariableListByGroupId, + deletePublishProfile, + renamePublishProfile, + getAppVersions, + downloadAppVersion, } from '../services'; import { commandWriter, configWriter } from './writer'; import { trustAppcircleCertificate } from '../security/trust-url-certificate'; @@ -214,19 +218,33 @@ const handleOrganizationCommand = async (command: ProgramCommand, params: any) = }; const handlePublishCommand = async (command: ProgramCommand, params: any) => { - if (command.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`) { + if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-create`) { const profileRes = await createPublishProfile({ platform: params.platform, name: params.name }); commandWriter(CommandTypes.PUBLISH, { fullCommandName: command.fullCommandName, data: profileRes, }); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profileList`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-list`) { const profiles = await getPublishProfiles({ platform: params.platform }); commandWriter(CommandTypes.PUBLISH, { fullCommandName: command.fullCommandName, data: profiles, }); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionUpload`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-delete`) { + const response = await deletePublishProfile(params); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: response, + }); + } + else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-rename`) { + const response = await renamePublishProfile(params); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: response, + }); + } + else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-version-upload`) { const spinner = createOra('Try to upload the app version').start(); try { const responseData = await uploadAppVersion(params); @@ -237,7 +255,7 @@ const handlePublishCommand = async (command: ProgramCommand, params: any) => { spinner.fail('Upload failed'); throw e; } - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionDelete`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-version-delete`) { const spinner = createOra('Try to remove the app version').start(); try { const responseData = await deleteAppVersion(params); @@ -248,7 +266,7 @@ const handlePublishCommand = async (command: ProgramCommand, params: any) => { spinner.fail('Remove failed'); throw e; } - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-startExistingFlow`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-start`) { const spinner = createOra('Publish flow starting').start(); const publish = await getPublishByAppVersion(params); const firstStep = publish.steps[0]; @@ -256,29 +274,53 @@ const handlePublishCommand = async (command: ProgramCommand, params: any) => { commandWriter(CommandTypes.PUBLISH, startResponse); spinner.text = `Publish started successfully.`; spinner.succeed(); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-versionDownload`) { - const spinner = createOra('Fetching app version download link').start(); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-version-download`) { + let spinner = createOra('Fetching app version download link').start(); try { + let downloadPath = path.resolve((params.path || '').replace('~', `${os.homedir}`)); const responseData = await getAppVersionDownloadLink(params); - commandWriter(CommandTypes.PUBLISH, responseData); - spinner.text = `App version download link fetched successfully.\n\nDownload Link: ${responseData}`; + const appVersions = await getAppVersions(params); + const appVersion = appVersions.find((appVersion: any) => appVersion.id === params.appVersionId); + if (!appVersion) { + spinner.fail(); + throw new Error('App version not found'); + } + spinner.text = `App version download link fetched successfully.`; + spinner.text = `Try to download the app version.`; + downloadPath = path.join(downloadPath, appVersion.fileName); + await downloadAppVersion({ url: responseData, path:downloadPath }); + spinner.text = `App version downloaded successfully.\n\nDownload Path: ${downloadPath}`; spinner.succeed(); } catch (e: any) { spinner.fail('Process failed'); throw e; } - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-markAsReleaseCandidate`) { - await setAppVersionReleaseCandidateStatus(params); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-setAsAutoPublish`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-version-markAsRC`) { + const response = await setAppVersionReleaseCandidateStatus({...params, releaseCandidate: true }); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: response, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-version-unmarkAsRC`) { + const response = await setAppVersionReleaseCandidateStatus({...params, releaseCandidate: false }); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: response, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-settings-autopublish`) { const publishProfileDetails = await getPublishProfileDetailById(params); - await switchPublishProfileAutoPublishSettings({ ...params, currentProfileSettings: publishProfileDetails.profileSettings }); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`) { + const response = await switchPublishProfileAutoPublishSettings({ ...params, currentProfileSettings: publishProfileDetails.profileSettings }); + commandWriter(CommandTypes.PUBLISH, { + fullCommandName: command.fullCommandName, + data: response, + }); + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-variable-group-list`) { const variableGroups = await getPublishVariableGroups(); commandWriter(CommandTypes.PUBLISH, { fullCommandName: command.fullCommandName, data: variableGroups, }); - } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`) { + } else if (command.fullCommandName === `${PROGRAM_NAME}-publish-variable-group-view`) { const variables = await getPublishVariableListByGroupId(params); commandWriter(CommandTypes.PUBLISH, { fullCommandName: command.fullCommandName, diff --git a/src/core/commands.ts b/src/core/commands.ts index d96de3b..bd63d9c 100644 --- a/src/core/commands.ts +++ b/src/core/commands.ts @@ -391,52 +391,9 @@ export const Commands: CommandType[] = [ longDescription: 'Manage publish module actions.', subCommands: [ { - command: 'createProfile', - description: 'Create a publish profile', - longDescription: 'Create a new publish profile', - params: [platformParam, - { - name: 'name', - description: 'Profile name', - type: CommandParameterTypes.STRING, - defaultValue: undefined, - valueType: 'string', - required: true, - } - ], - }, - { - command: 'profileList', - description: 'Publish profile list', - longDescription: 'Get list of publish profile', - params: [platformParam], - }, - { - command: 'versionUpload', - description: 'Upload a new app version', - longDescription: 'Upload a new version to selected publish profile', - params: [ - platformParam, - { - name: 'publishProfileId', - description: 'Publish Profile ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true - }, - { - name: 'app', - description: 'App path', - type: CommandParameterTypes.STRING, - valueType: 'path', - required: true - } - ], - }, - { - command: 'versionDelete', - description: 'Remove app version', - longDescription: 'Remove app version from selected publish profile', + command: 'start', + description: 'Start a publish', + longDescription: 'Starts a publish', params: [ platformParam, { @@ -456,125 +413,272 @@ export const Commands: CommandType[] = [ ], }, { - command: 'versionDownload', - description: 'Download app version', - longDescription: 'Download app version from selected publish profile', - params: [ - platformParam, + command: 'profile', + description: 'Publish profile actions', + longDescription: 'Publish profile actions', + params: [], + subCommands: [ { - name: 'publishProfileId', - description: 'Publish Profile ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: 'list', + description: 'Publish profile list', + longDescription: 'Get list of publish profile', + params: [platformParam], }, { - name: 'appVersionId', - description: 'App version', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true - } - ], - }, - { - command: 'markAsReleaseCandidate', - description: 'Mark/Unmark as Release Candidate', - longDescription: 'Mark/Unmark an app version as Release Candidate', - params: [ - platformParam, - { - name: 'publishProfileId', - description: 'Publish Profile ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: 'create', + description: 'Create a publish profile', + longDescription: 'Create a new publish profile', + params: [platformParam, + { + name: 'name', + description: 'Profile name', + type: CommandParameterTypes.STRING, + defaultValue: undefined, + valueType: 'string', + required: true, + } + ], }, { - name: 'appVersionId', - description: 'App version', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: 'rename', + description: 'Raname publish profile', + longDescription: 'Rename publish profile', + params: [platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'name', + description: 'New profile name', + type: CommandParameterTypes.STRING, + defaultValue: undefined, + valueType: 'string', + required: true, + } + ], }, { - name: 'releaseCandidate', - description: 'Release Candidate', - type: CommandParameterTypes.BOOLEAN, - valueType: 'boolean', - required: true - } - ], - }, - { - command: 'startExistingFlow', - description: 'Start a publish', - longDescription: 'Starts a publish', - params: [ - platformParam, - { - name: 'publishProfileId', - description: 'Publish Profile ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: 'delete', + description: 'Remove publish profile', + longDescription: 'Remove publish profile', + params: [platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], }, { - name: 'appVersionId', - description: 'App version', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true - } - ], - }, - { - command: 'setAsAutoPublish', - description: 'Set Publish Profile as Auto Publish', - longDescription: 'Start a publish process when a new version is received.', - params: [ - platformParam, - { - name: 'publishProfileId', - description: 'Publish Profile ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: 'version', + description: 'App version actions', + longDescription: 'App version actions', + params: [], + subCommands: [ + { + command: 'upload', + description: 'Upload a new app version', + longDescription: 'Upload a new version to given publish profile', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'app', + description: 'App path', + type: CommandParameterTypes.STRING, + valueType: 'path', + required: true + } + ], + }, + { + command: 'download', + description: 'Download app version', + longDescription: 'Download app version from selected publish profile', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'path', + description: '[OPTIONAL] The path for artifacts to be downloaded:', + longDescription:'[OPTIONAL] The path for artifacts to be downloaded: (Defaults to the current directory)', + type: CommandParameterTypes.STRING, + valueType: 'path', + required: false + } + ], + }, + { + command: 'delete', + description: 'Remove app version', + longDescription: 'Remove app version from selected publish profile', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + { + command: 'markAsRC', + description: 'Mark as Release Candidate', + longDescription: 'Mark an app version as Release Candidate', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + { + command: 'unmarkAsRC', + description: 'Unmark as Release Candidate', + longDescription: 'Unmark an app version as Release Candidate', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'appVersionId', + description: 'App version', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], + }, + ] }, { - name: 'enableAutoPublish', - description: 'Enable Auto Publish', - type: CommandParameterTypes.BOOLEAN, - valueType: 'boolean', - required: true + command: 'settings', + description: 'Publish profile settings', + longDescription: 'Publish profile settings', + params: [], + subCommands: [ + { + command: 'autopublish', + description: 'Set Publish Profile as Auto Publish', + longDescription: 'Start a publish process when a new version is received.', + params: [ + platformParam, + { + name: 'publishProfileId', + description: 'Publish Profile ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + }, + { + name: 'enable', + description: 'Enable Auto Publish', + type: CommandParameterTypes.BOOLEAN, + valueType: 'boolean', + required: true + } + ], + }, + ] } - ], + ] }, { - command: 'publishVariables', + command: 'variable', description: 'Publish Variables', longDescription: 'Publish Variables', params: [], subCommands: [ { - command: 'groups', - description: 'Groups', - longDescription: 'Get list of publish variable group', + command: 'group', + description: 'Group Actions', + longDescription: 'Publish variable group actions', params: [], - }, - { - command: 'variables', - description: 'Publish Variable List', - longDescription: 'View publish variables by group', - params: [ + subCommands:[ { - name: 'publishVariableGroupId', - description: 'Variable Group ID', - type: CommandParameterTypes.SELECT, - valueType: 'uuid', - required: true + command: "list", + description: 'List groups', + longDescription: 'Publish variable group actions', + params: [], + }, + // { + // command: "create", + // description: 'Create new group', + // longDescription: 'Create a new publish variable group', + // params: [{ + // name: 'name', + // description: 'Group name', + // type: CommandParameterTypes.STRING, + // defaultValue: undefined, + // valueType: 'string', + // required: true, + // }], + // }, + { + command: "view", + description: 'View items of group', + longDescription: 'View items of publish variable group', + params: [ + { + name: 'publishVariableGroupId', + description: 'Variable Group ID', + type: CommandParameterTypes.SELECT, + valueType: 'uuid', + required: true + } + ], } - ], + ] } ] } diff --git a/src/core/writer.ts b/src/core/writer.ts index f35fd55..c6e51b4 100644 --- a/src/core/writer.ts +++ b/src/core/writer.ts @@ -287,16 +287,25 @@ const writersMap: { [key in CommandTypes]: (data: any) => void } = { } else { console.log(data.data); } - }, + }, [CommandTypes.PUBLISH]: (data: any) => { - if(data.fullCommandName === `${PROGRAM_NAME}-publish-createProfile`){ + if(data.fullCommandName === `${PROGRAM_NAME}-publish-profile-create`){ + console.table( + [{ 'Id:': data.data.id, + 'Name:': data.data.name, + 'Created:': data.data.createDate ? moment(data.data.createDate).calendar() : '-', + }] + ) + }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-profile-rename`){ console.table( [{ 'Id:': data.data.id, 'Name:': data.data.name, 'Created:': data.data.createDate ? moment(data.data.createDate).calendar() : '-', + 'Updated:': data.data.updateDate ? moment(data.data.updateDate).calendar() : '-', }] ) - } else if(data.fullCommandName === `${PROGRAM_NAME}-publish-profileList`){ + } + else if(data.fullCommandName === `${PROGRAM_NAME}-publish-profile-list`){ data.data.length > 0 ? console.table( data.data.map((publishProfile: any) => ({ @@ -312,7 +321,7 @@ const writersMap: { [key in CommandTypes]: (data: any) => void } = { Updated: publishProfile.updateDate ? moment(publishProfile.updateDate).calendar() : '-', })) ) : console.log(' No publish profile found'); - }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-groups`){ + }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-variable-group-list`){ data.data.length > 0 ? console.table( data.data.map((group: any) => ({ 'Group Id': group.id, @@ -321,13 +330,32 @@ const writersMap: { [key in CommandTypes]: (data: any) => void } = { Updated: group.updateDate ? moment(group.updateDate).calendar() : '-', })) ) : console.log(' No publish variable group found'); - }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-publishVariables-variables`){ + }else if(data.fullCommandName === `${PROGRAM_NAME}-publish-variable-group-view`){ data.data.length > 0 ? console.table( data.data.map((variable: any) => ({ 'Key Name': variable.key, 'Key Value': variable.isSecret ? '********' : variable.value, })) ) : console.log(' No publish variable found'); + }else if(data.fullCommandName ===`${PROGRAM_NAME}-publish-profile-settings-autopublish`){ + console.table( + [{ 'Id:': data.data.id, + 'Name:': data.data.name, + 'Created:': data.data.createDate ? moment(data.data.createDate).calendar() : '-', + 'Updated:': data.data.updateDate ? moment(data.data.updateDate).calendar() : '-', + 'Auto Publish': data.data.profileSettings.whenNewVersionRecieved ? 'Yes' : 'No', + }] + ) + }else if(data.fullCommandName ===`${PROGRAM_NAME}-publish-profile-version-markAsRC` || data.fullCommandName ===`${PROGRAM_NAME}-publish-profile-version-unmarkAsRC`){ + console.table( + [{ 'Id:': data.data.id, + 'Name:': data.data.name, + 'Unique Name': data.data.uniqueName, + 'Created:': data.data.createDate ? moment(data.data.createDate).calendar() : '-', + 'Updated:': data.data.updateDate ? moment(data.data.updateDate).calendar() : '-', + 'Release Candidate': data.data.releaseCandidate ? 'Yes' : 'No', + }] + ) } else { console.log(data.data) diff --git a/src/services/index.ts b/src/services/index.ts index 68ea2c3..8992fcc 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -36,8 +36,6 @@ export async function createDistributionProfile(options: OptionsType<{ name: str return response.data; } -} - export async function getTestingGroups(options: OptionsType) { const response = await appcircleApi.get(`distribution/v2/testing-groups`, { headers: getHeaders(), diff --git a/src/services/publish.ts b/src/services/publish.ts index 0485666..e699534 100644 --- a/src/services/publish.ts +++ b/src/services/publish.ts @@ -3,6 +3,7 @@ import fs from 'fs'; import FormData from 'form-data'; import { ProgramError } from '../core/ProgramError'; import { OptionsType, appcircleApi, getHeaders } from './api'; +import axios from 'axios'; export async function createPublishProfile(options: OptionsType<{ platform: string, name: string }>) { const response = await appcircleApi.post( @@ -12,6 +13,22 @@ export async function createPublishProfile(options: OptionsType<{ platform: stri ); return response.data; } + +export async function deletePublishProfile(options: OptionsType<{ platform: string, publishProfileId: string }>) { + const response = await appcircleApi.delete( + `publish/v2/profiles/${options.platform}/${options.publishProfileId}`, + { headers: getHeaders() } + ); + return response.data; + } + export async function renamePublishProfile(options: OptionsType<{ platform: string, publishProfileId: string, name: string }>) { + const response = await appcircleApi.patch( + `publish/v2/profiles/${options.platform}/${options.publishProfileId}`, + { name : options.name}, + { headers: getHeaders() } + ); + return response.data; + } export async function getPublishProfiles(options: OptionsType<{ platform: string }>) { const response = await appcircleApi.get( @@ -63,9 +80,9 @@ export async function createPublishProfile(options: OptionsType<{ platform: stri return response.data; } - export async function switchPublishProfileAutoPublishSettings(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, enableAutoPublish: boolean, currentProfileSettings: any }>) { + export async function switchPublishProfileAutoPublishSettings(options: OptionsType<{ publishProfileId: string, platform:string, appVersionId: string, enable: boolean, currentProfileSettings: any }>) { const response = await appcircleApi.patch(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`,{ - profileSettings: {...options.currentProfileSettings , whenNewVersionRecieved: options.enableAutoPublish } + profileSettings: {...options.currentProfileSettings , whenNewVersionRecieved: options.enable } }, { headers: getHeaders() @@ -119,14 +136,35 @@ export async function createPublishProfile(options: OptionsType<{ platform: stri return downloadResponse.data; } export async function getPublishProfileDetailById(options: OptionsType<{ publishProfileId: string, platform:string }>) { - const response = await appcircleApi.get(`publish/v2/profiles/${options.platform}/${options.publishProfileId}`, { headers: getHeaders() } ); - return response.data; } - \ No newline at end of file + export async function downloadAppVersion(options: OptionsType<{ url: string, path: string }>) { + + + const downloadResponse = await axios.get(options.url, { + responseType: 'stream', + }); + return new Promise((resolve, reject) => { + const writer = fs.createWriteStream(options.path); + downloadResponse.data.pipe(writer); + let error: any = null; + writer.on('error', (err) => { + error = err; + writer.close(); + reject(err); + }); + writer.on('close', () => { + if (!error) { + resolve(true); + } + //no need to call the reject here, as it will have been called in the + //'error' stream; + }); + }); + } \ No newline at end of file From 8d472f7c1a6486dfc77f31fbd33068807acf5677 Mon Sep 17 00:00:00 2001 From: "burak.yildirim" Date: Sun, 7 Apr 2024 17:12:45 +0300 Subject: [PATCH 5/6] 1.3.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1fee47..d42848a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@appcircle/cli", - "version": "1.2.0", + "version": "1.3.0-beta.1", "description": "CLI tool for running Appcircle services from the command line", "main": "bin/appcircle", "bin": { From 438a9e3cb281ae6ffeb2cebb495ff5f562cafd12 Mon Sep 17 00:00:00 2001 From: "burak.yildirim" Date: Sun, 7 Apr 2024 17:22:25 +0300 Subject: [PATCH 6/6] add platform control for cli runner --- src/core/command-runner.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/command-runner.ts b/src/core/command-runner.ts index 0c916b9..10c21a8 100644 --- a/src/core/command-runner.ts +++ b/src/core/command-runner.ts @@ -218,6 +218,9 @@ const handleOrganizationCommand = async (command: ProgramCommand, params: any) = }; const handlePublishCommand = async (command: ProgramCommand, params: any) => { + if(params.platform && !['ios','android'].includes(params.platform)){ + throw new ProgramError(`Invalid platform(${params.platform}). Supported platforms: ios, android`); + } if (command.fullCommandName === `${PROGRAM_NAME}-publish-profile-create`) { const profileRes = await createPublishProfile({ platform: params.platform, name: params.name }); commandWriter(CommandTypes.PUBLISH, {