From b800eacecc39087a0eaefa2da71f86d99e116f95 Mon Sep 17 00:00:00 2001 From: Thomas Timmer <39119640+thomas9911@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:23:16 +0200 Subject: [PATCH] feat: add blocks publish --all command (#466) * feat: add blocks publish --all command * feat: add blocks release command --------- Co-authored-by: Thomas Timmer --- src/bb-blocks-publish.ts | 29 +++++---- src/bb-blocks-release.ts | 24 ++++++++ src/bb-blocks.ts | 5 +- src/blocks/releaseBlocks.ts | 116 ++++++++++++++++++++++++++++++++++++ src/types.ts | 2 +- 5 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 src/bb-blocks-release.ts create mode 100644 src/blocks/releaseBlocks.ts diff --git a/src/bb-blocks-publish.ts b/src/bb-blocks-publish.ts index a8ca4a0c..e97f9d64 100644 --- a/src/bb-blocks-publish.ts +++ b/src/bb-blocks-publish.ts @@ -23,7 +23,7 @@ import { validateBlock, } from './validations/function-block-validations'; -program.name('bb blocks publish').parse(process.argv); +program.option('--all').name('bb blocks publish').parse(process.argv); const workingDir = process.cwd(); const baseBlocksPath = path.join(workingDir, 'blocks'); @@ -79,15 +79,24 @@ void (async (): Promise => { title: path.basename(block, '.json'), value: block, })); - const { selected } = (await prompts([ - { - type: 'multiselect', - name: 'selected', - message: 'Which blocks do you want to publish?', - choices, - instructions: false, - }, - ])) as { selected: string[] }; + const { all } = program.opts(); + + let selected: string[] = []; + + if (all) { + selected = blocks; + } else { + const results = (await prompts([ + { + type: 'multiselect', + name: 'selected', + message: 'Which blocks do you want to publish?', + choices, + instructions: false, + }, + ])) as { selected: string[] }; + selected = results.selected; + } selected.forEach((jsonFile) => { // eslint-disable-next-line no-void diff --git a/src/bb-blocks-release.ts b/src/bb-blocks-release.ts new file mode 100644 index 00000000..3532cf54 --- /dev/null +++ b/src/bb-blocks-release.ts @@ -0,0 +1,24 @@ +import program from 'commander'; +import releaseBlocks from './blocks/releaseBlocks'; + +program + .usage('[options] [blockIds...]') + .option( + '-a, --all', + 'release all dev blocks that are attached to your account', + ) + .name('bb blocks release') + .parse(process.argv); + +const { all }: { all?: boolean } = program.opts(); +const blockIds = program.args; + +if (!all && !blockIds.length) { + console.error('No block IDs provided'); + process.exit(1); +} + +// eslint-disable-next-line no-void +void (async (): Promise => { + await releaseBlocks({ all, blockIds }); +})(); diff --git a/src/bb-blocks.ts b/src/bb-blocks.ts index a4db9bd2..eef71645 100644 --- a/src/bb-blocks.ts +++ b/src/bb-blocks.ts @@ -4,11 +4,11 @@ import program from 'commander'; /* internal dependencies */ -import { CommandBlocks } from './types'; +import type { CommandBlocks } from './types'; /* setup */ -const availableCommands: CommandBlocks[] = ['publish', 'new']; +const availableCommands: CommandBlocks[] = ['publish', 'release', 'new']; /* process arguments */ @@ -17,6 +17,7 @@ program .name('bb blocks') .command('new [blocks-name]', 'Initialize a new block') .command('publish', 'publish blocks of current working directory') + .command('release', 'release dev blocks') .on('command:*', ([command]: string[]): void => { if (!availableCommands.includes(command as CommandBlocks)) { console.error('Invalid command: %s\n', command); diff --git a/src/blocks/releaseBlocks.ts b/src/blocks/releaseBlocks.ts new file mode 100644 index 00000000..a83e4a1a --- /dev/null +++ b/src/blocks/releaseBlocks.ts @@ -0,0 +1,116 @@ +import fetch from 'node-fetch'; +import type { Response, RequestInit } from 'node-fetch'; +import Config from '../functions/config'; +import FusionAuth from '../utils/login'; + +const GET_DEV_BLOCKS = '/blocks/my-dev-blocks'; +const POST_RELEASE_BLOCKS = '/blocks/release'; + +const sendBlockstoreRequest = async ( + urlPath: string, + method: string, + body: RequestInit['body'], + config: Config, + fusionAuth: FusionAuth, + applicationId: string, +): Promise => { + const url = `${config.blockstoreApiUrl}${urlPath}`; + return fetch(url, { + agent: config.agent, + method, + body, + headers: { + 'content-type': 'application/json', + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + Authorization: `Bearer ${fusionAuth.jwt()}`, + ApplicationId: applicationId, + Accept: 'application/json', + }, + }).then(async (res) => { + if (res.status === 401 || res.status === 403) { + await fusionAuth.ensureLogin(); + return sendBlockstoreRequest( + urlPath, + method, + body, + config, + fusionAuth, + applicationId, + ); + } + + return res; + }); +}; + +const fetchAllDevBlocks = async ( + config: Config, + fusionAuth: FusionAuth, + applicationId: string, +): Promise => { + return sendBlockstoreRequest( + GET_DEV_BLOCKS, + 'GET', + undefined, + config, + fusionAuth, + applicationId, + ); +}; + +const releaseBlocksInBlockstore = async ( + blockIds: string[], + config: Config, + fusionAuth: FusionAuth, + applicationId: string, +): Promise => { + const response = await sendBlockstoreRequest( + POST_RELEASE_BLOCKS, + 'POST', + JSON.stringify({ block_ids: blockIds }), + config, + fusionAuth, + applicationId, + ); + if (!response.ok) { + await response + .text() + .then((text) => + console.error(`Failed to release blocks in Blockstore: ${text}`), + ); + return false; + } + return true; +}; + +const releaseBlocks = async ({ + all, + blockIds, +}: { + all?: boolean; + blockIds: string[]; +}): Promise => { + const config = new Config(); + const fusionAuth = new FusionAuth(config); + const applicationId = await config.applicationId(); + if (!applicationId) { + throw new Error( + "Couldn't publish block(s), Error: application id not found", + ); + } + + let blockIdsToBeReleased: string[] = blockIds; + if (all) { + const res = await fetchAllDevBlocks(config, fusionAuth, applicationId); + blockIdsToBeReleased = (await res.json()) as string[]; + } + + return releaseBlocksInBlockstore( + blockIdsToBeReleased, + config, + fusionAuth, + applicationId, + ); +}; + +export default releaseBlocks; diff --git a/src/types.ts b/src/types.ts index bd0259b0..1417e2b6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -32,7 +32,7 @@ export type CommandFunctions = | 'bump' | 'test'; -export type CommandBlocks = 'publish' | 'new'; +export type CommandBlocks = 'publish' | 'release' | 'new'; export type CommandInteractions = 'generate';