From 357141b9e3db4449208a6f503d0101c4bc9b6fb9 Mon Sep 17 00:00:00 2001 From: Edie Lemoine Date: Thu, 8 Feb 2024 13:11:19 +0100 Subject: [PATCH] build(release): add git functionality --- apps/delivery-options/release.config.cjs | 6 +++-- .../src/prepare/gitCommit.ts | 22 +++++++++++++++++++ .../src/prepare/index.ts | 8 +++++++ .../updatePackageJsonVersions.ts} | 6 ++--- libs/semantic-release-plugin/src/types.ts | 1 + .../src/utils/executeWithErrorHandling.ts | 14 ++++++++++++ .../src/utils/index.ts | 1 + .../src/verifyConditions.ts | 10 +++++++-- 8 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 libs/semantic-release-plugin/src/prepare/gitCommit.ts create mode 100644 libs/semantic-release-plugin/src/prepare/index.ts rename libs/semantic-release-plugin/src/{prepare.ts => prepare/updatePackageJsonVersions.ts} (74%) create mode 100644 libs/semantic-release-plugin/src/utils/executeWithErrorHandling.ts diff --git a/apps/delivery-options/release.config.cjs b/apps/delivery-options/release.config.cjs index f6f5ee33..c49c5213 100644 --- a/apps/delivery-options/release.config.cjs +++ b/apps/delivery-options/release.config.cjs @@ -21,8 +21,10 @@ module.exports = { addGitHubActionsOutputPlugin(), addReleaseNotesGeneratorPlugin(), addChangelogPlugin(), - '@myparcel-do/semantic-release-plugin', addGitHubPlugin(), - addGitPlugin(), + /* + * Includes npm and git functionality + */ + '@myparcel-do/semantic-release-plugin', ], }; diff --git a/libs/semantic-release-plugin/src/prepare/gitCommit.ts b/libs/semantic-release-plugin/src/prepare/gitCommit.ts new file mode 100644 index 00000000..89554e30 --- /dev/null +++ b/libs/semantic-release-plugin/src/prepare/gitCommit.ts @@ -0,0 +1,22 @@ +import {executeWithErrorHandling, hasErrors, throwIfHasErrors} from '../utils'; +import {type ContextWithNextRelease} from '../types'; + +export const gitCommit = async (context: ContextWithNextRelease): Promise => { + const {env, cwd, nextRelease} = context; + + await executeWithErrorHandling( + 'git', + ['commit', '-am', `chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}`], + { + cwd, + env, + stdio: 'inherit', + }, + ); + + if (!hasErrors()) { + await executeWithErrorHandling('git', ['push', '--tags'], {env, cwd}); + } + + throwIfHasErrors(); +}; diff --git a/libs/semantic-release-plugin/src/prepare/index.ts b/libs/semantic-release-plugin/src/prepare/index.ts new file mode 100644 index 00000000..cbb6a3f7 --- /dev/null +++ b/libs/semantic-release-plugin/src/prepare/index.ts @@ -0,0 +1,8 @@ +import {type PrepareCmd} from '../types'; +import {updatePackageJsonVersions} from './updatePackageJsonVersions'; +import {gitCommit} from './gitCommit'; + +export const prepare: PrepareCmd = async (_, context) => { + await updatePackageJsonVersions(context); + await gitCommit(context); +}; diff --git a/libs/semantic-release-plugin/src/prepare.ts b/libs/semantic-release-plugin/src/prepare/updatePackageJsonVersions.ts similarity index 74% rename from libs/semantic-release-plugin/src/prepare.ts rename to libs/semantic-release-plugin/src/prepare/updatePackageJsonVersions.ts index d2034de4..1c75193f 100644 --- a/libs/semantic-release-plugin/src/prepare.ts +++ b/libs/semantic-release-plugin/src/prepare/updatePackageJsonVersions.ts @@ -1,7 +1,7 @@ -import {getPackageJson, execute, addError, throwIfHasErrors} from './utils'; -import {type PrepareCmd} from './types'; +import {getPackageJson, execute, addError, throwIfHasErrors} from '../utils'; +import {type ContextWithNextRelease} from '../types'; -export const prepare: PrepareCmd = async (_, context) => { +export const updatePackageJsonVersions = async (context: ContextWithNextRelease): Promise => { const {cwd, env, logger, nextRelease} = context; const pkg = await getPackageJson(context); diff --git a/libs/semantic-release-plugin/src/types.ts b/libs/semantic-release-plugin/src/types.ts index dae87109..3157f968 100644 --- a/libs/semantic-release-plugin/src/types.ts +++ b/libs/semantic-release-plugin/src/types.ts @@ -19,6 +19,7 @@ export interface ContextWithNextRelease extends Context { nextRelease: { version: string; channel: string; + notes: string; }; } diff --git a/libs/semantic-release-plugin/src/utils/executeWithErrorHandling.ts b/libs/semantic-release-plugin/src/utils/executeWithErrorHandling.ts new file mode 100644 index 00000000..5dbdee6e --- /dev/null +++ b/libs/semantic-release-plugin/src/utils/executeWithErrorHandling.ts @@ -0,0 +1,14 @@ +import {type Options} from 'execa'; +import {execute} from './execute'; +import {addError} from './errorHandling'; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export const executeWithErrorHandling = async (command: string, args: string[], options?: Options) => { + const result = await execute(command, args, options); + + if (result.stderr) { + addError(new Error(`Command "${command} ${args.join(' ')}" failed: ${result.stderr}`)); + } + + return result; +}; diff --git a/libs/semantic-release-plugin/src/utils/index.ts b/libs/semantic-release-plugin/src/utils/index.ts index 79962521..2958b26b 100644 --- a/libs/semantic-release-plugin/src/utils/index.ts +++ b/libs/semantic-release-plugin/src/utils/index.ts @@ -1,3 +1,4 @@ export * from './errorHandling'; export * from './execute'; +export * from './executeWithErrorHandling'; export * from './getPackageJson'; diff --git a/libs/semantic-release-plugin/src/verifyConditions.ts b/libs/semantic-release-plugin/src/verifyConditions.ts index e8311545..945d373c 100644 --- a/libs/semantic-release-plugin/src/verifyConditions.ts +++ b/libs/semantic-release-plugin/src/verifyConditions.ts @@ -1,10 +1,16 @@ -import {addError, throwIfHasErrors} from './utils'; +import {addError, throwIfHasErrors, execute} from './utils'; import {type VerifyConditionsCmd} from './types'; -export const verifyConditions: VerifyConditionsCmd = (_, {env}) => { +export const verifyConditions: VerifyConditionsCmd = async (_, {env}) => { if (!env.NPM_TOKEN) { addError(new Error('NPM_TOKEN environment variable is required')); } + const result = await execute('git', ['push', 'origin', '--dry-run'], {env, stdio: 'ignore'}); + + if (result.stderr) { + addError(new Error(result.stderr)); + } + throwIfHasErrors(); };