aberlaas-release 2.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ import { _ } from 'golgoth';
2
+ import {
3
+ consoleInfo,
4
+ consoleWarn,
5
+ env,
6
+ firostError,
7
+ prompt,
8
+ readJson,
9
+ run,
10
+ sleep,
11
+ wrap,
12
+ write,
13
+ } from 'firost';
14
+ import { hostGitPath, hostPackagePath } from 'aberlaas-helper';
15
+
16
+ export const __ = {
17
+ /**
18
+ * Ensures the user is logged in to npm by checking authentication status and prompting for login if needed.
19
+ * @returns {boolean|undefined} Returns true if already logged in, undefined if login was required and completed
20
+ * @throws {Error} Throws error if npm authentication fails for reasons other than E401 unauthorized
21
+ */
22
+ async ensureNpmLogin() {
23
+ try {
24
+ await __.npmRun('whoami');
25
+ return true;
26
+ } catch (err) {
27
+ if (err.code == 'ABERLAAS_RELEASE_NPM_ERROR_E401') {
28
+ await __.waitForNpmLogin();
29
+ return;
30
+ }
31
+ throw err;
32
+ }
33
+ },
34
+
35
+ /**
36
+ * Executes an npm command and returns its output
37
+ * @param {string} command - The npm command to execute (without 'npm' prefix)
38
+ * @returns {string} The stdout output from the npm command
39
+ * @throws {Error} Throws a formatted error if the npm command fails
40
+ */
41
+ async npmRun(command) {
42
+ try {
43
+ const { stdout } = await __.run(`npm ${command}`, {
44
+ stdout: false,
45
+ stderr: false,
46
+ });
47
+ return stdout;
48
+ } catch ({ stderr }) {
49
+ const errorLines = _.split(stderr, '\n');
50
+
51
+ // Identify known npm errors
52
+ if (_.startsWith(errorLines[0], 'npm error code')) {
53
+ const npmErrorCode = _.replace(errorLines[0], 'npm error code ', '');
54
+ const npmErrorMessage = _.chain(errorLines).slice(1).join('\n').value();
55
+ throw firostError(
56
+ `ABERLAAS_RELEASE_NPM_ERROR_${npmErrorCode}`,
57
+ npmErrorMessage,
58
+ );
59
+ }
60
+
61
+ // Throw unknown errors up
62
+ throw firostError('ABERLAAS_RELEASE_NPM_UNKNOWN_ERROR', stderr);
63
+ }
64
+ },
65
+
66
+ /**
67
+ * Prompts the user to create and configure an npm authentication token when not logged in.
68
+ * Opens the npm token creation page in browser, guides user through token setup,
69
+ * collects the token, and saves it to .npmrc file.
70
+ */
71
+ async waitForNpmLogin() {
72
+ __.consoleWarn('You are not currently authentified to npm.');
73
+
74
+ await __.displayLoginInstructions();
75
+ await __.openBrowserForToken();
76
+ await __.saveNpmToken();
77
+
78
+ // Try again
79
+ await __.ensureNpmLogin();
80
+ },
81
+
82
+ /**
83
+ * Displays login instructions to the user
84
+ */
85
+ async displayLoginInstructions() {
86
+ const rootPackage = await readJson(hostPackagePath('package.json'));
87
+ const packageName = rootPackage.name;
88
+ const tokenName = __.generateTokenName(packageName);
89
+
90
+ __.consoleInfo('');
91
+ __.consoleInfo('Your npm token page will open.');
92
+ __.consoleInfo('We suggest you fill in the following informations:');
93
+ __.consoleInfo('');
94
+ __.consoleInfo('GENERAL');
95
+ __.consoleInfo(`Token name*: ${tokenName}`);
96
+ __.consoleInfo('☑️ Bypass two-factor authentication (2FA)');
97
+ __.consoleInfo('');
98
+ __.consoleInfo('PACKAGE AND SCOPES');
99
+ __.consoleInfo('Permissions: Read and write');
100
+ __.consoleInfo(`🔘 Only select packages and scopes: ${packageName}`);
101
+ __.consoleInfo('');
102
+ __.consoleInfo('EXPIRATION');
103
+ __.consoleInfo('Expiration date: 90 days');
104
+ __.consoleInfo('');
105
+ },
106
+
107
+ /**
108
+ * Generates a suggested token name from package name
109
+ * @param {string} packageName - The package name
110
+ * @returns {string} The suggested token name
111
+ */
112
+ generateTokenName(packageName) {
113
+ const cleanPackageName = _.chain(packageName)
114
+ .replace('-', '_')
115
+ .replace('@', '')
116
+ .replace('/', '_')
117
+ .toUpper()
118
+ .value();
119
+ return `ABERLAAS_RELEASE_${cleanPackageName}`;
120
+ },
121
+
122
+ /**
123
+ * Opens browser for token creation
124
+ */
125
+ async openBrowserForToken() {
126
+ const npmUsername = await __.getNpmUsername();
127
+ const tokenUrl = __.buildTokenUrl(npmUsername);
128
+
129
+ await __.prompt('Press Enter to open the webpage');
130
+ __.run(`$BROWSER ${tokenUrl}`, { shell: true, stderr: false });
131
+ await __.sleep(2000);
132
+ },
133
+
134
+ /**
135
+ * Gets the NPM username from environment variable or prompts user for input
136
+ * @returns {string} The NPM username
137
+ */
138
+ async getNpmUsername() {
139
+ return (
140
+ __.env('ABERLAAS_NPM_USERNAME') || (await __.prompt('NPM Username: '))
141
+ );
142
+ },
143
+
144
+ /**
145
+ * Builds the npm token creation URL for a given username
146
+ * @param {string} npmUsername - The npm username
147
+ * @returns {string} The token creation URL
148
+ */
149
+ buildTokenUrl(npmUsername) {
150
+ return `https://www.npmjs.com/settings/${npmUsername}/tokens/granular-access-tokens/new`;
151
+ },
152
+
153
+ /**
154
+ * Saves the npm token to .npmrc file
155
+ */
156
+ async saveNpmToken() {
157
+ const npmToken = await __.prompt('Enter you new token here:');
158
+ const npmrcContent = `//registry.npmjs.org/:_authToken=${npmToken}`;
159
+ const npmrcPath = hostGitPath('.npmrc');
160
+ await write(npmrcContent, npmrcPath);
161
+ },
162
+ run,
163
+ env,
164
+ prompt,
165
+ consoleWarn,
166
+ consoleInfo,
167
+ sleep,
168
+ };
169
+
170
+ export const ensureNpmLogin = wrap(__, 'ensureNpmLogin');
@@ -0,0 +1,137 @@
1
+ import { _ } from 'golgoth';
2
+ import { consoleInfo, firostError, run as firostRun } from 'firost';
3
+ import { hostGitRoot, yarnRun } from 'aberlaas-helper';
4
+ import Gilmore from 'gilmore';
5
+ import { ensureNpmLogin } from './ensureNpmLogin.js';
6
+
7
+ export const __ = {
8
+ /**
9
+ * Validates that the provided bump type is one of the accepted semantic
10
+ * versioning types, or empty for auto-detection.
11
+ * @param {object} cliArgs Release options
12
+ * @returns {void} - Returns nothing if valid, throws error if invalid
13
+ * @throws {Error} Throws ABERLAAS_RELEASE_UNKNOWN_BUMP_TYPE error if bumpType is provided but not 'patch', 'minor', or 'major'
14
+ */
15
+ ensureCorrectBumpType(cliArgs) {
16
+ const bumpType = cliArgs._[0];
17
+
18
+ // If no bump type provided, allow it (will be auto-detected)
19
+ if (_.isEmpty(bumpType)) {
20
+ return true;
21
+ }
22
+
23
+ // If bump type is provided, validate it
24
+ if (_.includes(['patch', 'minor', 'major'], bumpType)) {
25
+ return true;
26
+ }
27
+
28
+ throw firostError(
29
+ 'ABERLAAS_RELEASE_UNKNOWN_BUMP_TYPE',
30
+ 'Bump type should be either major, minor or patch (or omitted for auto-detection)',
31
+ );
32
+ },
33
+
34
+ /**
35
+ * Ensures the repository is on the main branch before allowing a release
36
+ * @param {object} repo - The repository object with branch operations
37
+ * @returns {Promise<boolean>} True if on main branch
38
+ * @throws {Error} Throws ABERLAAS_RELEASE_NOT_ON_MAIN_BRANCH error if not on main branch
39
+ */
40
+ async ensureCorrectBranch(repo) {
41
+ const currentBranch = await repo.currentBranchName();
42
+ if (currentBranch == 'main') {
43
+ return true;
44
+ }
45
+ throw firostError(
46
+ 'ABERLAAS_RELEASE_NOT_ON_MAIN_BRANCH',
47
+ 'You must be on branch main to release.',
48
+ );
49
+ },
50
+
51
+ /**
52
+ * Ensures the repository has no uncommitted changes before proceeding with operations
53
+ * @param {object} repo - The repository object to check status on
54
+ * @returns {Promise<boolean>} Returns true if repository is clean
55
+ * @throws {Error} Throws ABERLAAS_RELEASE_NOT_CLEAN_DIRECTORY error if uncommitted changes exist
56
+ */
57
+ async ensureCleanRepository(repo) {
58
+ const changes = await repo.status();
59
+ if (_.isEmpty(changes)) {
60
+ return true;
61
+ }
62
+ throw firostError(
63
+ 'ABERLAAS_RELEASE_NOT_CLEAN_DIRECTORY',
64
+ 'Your working directory must be clean, with no uncommitted changes.',
65
+ );
66
+ },
67
+
68
+ /**
69
+ * Ensures that all tests are passing before proceeding with a release
70
+ * @param {object} cliArgs Release options
71
+ * @returns {Promise<void>} A promise that resolves if tests pass, rejects with ABERLAAS_RELEASE_TESTS_FAILING error if tests fail
72
+ */
73
+ async ensureTestsArePassing(cliArgs = {}) {
74
+ if (cliArgs['skip-test']) {
75
+ return false;
76
+ }
77
+ __.consoleInfo('Running tests...');
78
+ try {
79
+ await __.yarnRun('test --failFast');
80
+ return true;
81
+ } catch (err) {
82
+ throw firostError('ABERLAAS_RELEASE_TESTS_FAILING', err.message);
83
+ }
84
+ },
85
+
86
+ /**
87
+ * Ensures that linting passes by running the lint process and throwing an error if it fails
88
+ * @param {object} cliArgs Release options
89
+ * @returns {Promise<void>} A promise that resolves if linting passes
90
+ * @throws {Error} Throws ABERLAAS_RELEASE_LINT_FAILING error if linting fails
91
+ */
92
+ async ensureLintIsPassing(cliArgs = {}) {
93
+ if (cliArgs['skip-lint']) {
94
+ return false;
95
+ }
96
+ __.consoleInfo('Running lint...');
97
+ try {
98
+ await __.yarnRun('lint');
99
+ return true;
100
+ } catch (err) {
101
+ throw firostError('ABERLAAS_RELEASE_LINT_FAILING', err.message);
102
+ }
103
+ },
104
+
105
+ consoleInfo,
106
+ ensureNpmLogin,
107
+ firostRun,
108
+ yarnRun,
109
+ };
110
+
111
+ /**
112
+ * Validate all pre-conditions before starting the release
113
+ * @param {object} cliArgs Release options
114
+ * @param {boolean} cliArgs.skipTest Skip test execution
115
+ * @param {boolean} cliArgs.skipLint Skip lint execution
116
+ * @returns {Promise<void>}
117
+ */
118
+ export async function ensureValidSetup(cliArgs = {}) {
119
+ __.ensureCorrectBumpType(cliArgs);
120
+
121
+ const repo = new Gilmore(hostGitRoot());
122
+
123
+ // Need to be on branch main
124
+ await __.ensureCorrectBranch(repo);
125
+
126
+ // Need to have a clean directory
127
+ await __.ensureCleanRepository(repo);
128
+
129
+ // Check npm login
130
+ await __.ensureNpmLogin();
131
+
132
+ // Check tests are passing
133
+ await __.ensureTestsArePassing(cliArgs);
134
+
135
+ // Check lint is passing
136
+ await __.ensureLintIsPassing(cliArgs);
137
+ }
@@ -0,0 +1,111 @@
1
+ import { _, pMap } from 'golgoth';
2
+ import { glob, readJson } from 'firost';
3
+ import { hostGitPath, hostGitRoot } from 'aberlaas-helper';
4
+ import { getGitDiff, parseCommits } from 'changelogen';
5
+ import semver from 'semver';
6
+
7
+ export const __ = {
8
+ /**
9
+ * Gets all packages that need to be released
10
+ * @returns {Array<{filepath: string, content: object}>} Array of packages with their filepath and content
11
+ */
12
+ async getAllPackagesToRelease() {
13
+ const rootPackagePath = hostGitPath('package.json');
14
+ const rootPackageContent = await readJson(rootPackagePath);
15
+ const workspaces = rootPackageContent.workspaces;
16
+
17
+ // If no workspaces, this is the package to publish
18
+ if (!workspaces) {
19
+ if (rootPackageContent.private) {
20
+ return [];
21
+ }
22
+ return [
23
+ {
24
+ filepath: rootPackagePath,
25
+ content: rootPackageContent,
26
+ },
27
+ ];
28
+ }
29
+
30
+ // If workspaces, we get the packages of all those workspaces
31
+ const rootPath = hostGitRoot();
32
+ const rawList = await pMap(workspaces, async (workspacePattern) => {
33
+ const packagesPath = await glob(
34
+ `${rootPath}/${workspacePattern}/package.json`,
35
+ );
36
+ const packagesData = await pMap(packagesPath, async (filepath) => {
37
+ const content = await readJson(filepath);
38
+ if (content.private) {
39
+ return false;
40
+ }
41
+ return {
42
+ filepath,
43
+ content,
44
+ };
45
+ });
46
+ return _.compact(packagesData);
47
+ });
48
+
49
+ return _.flatten(rawList);
50
+ },
51
+ /**
52
+ * Determines the appropriate semantic version bump type based on CLI arguments or git commit analysis
53
+ * @param {object} [cliArgs={}] - Command line arguments object containing potential bump type
54
+ * @param {string} currentVersion - The current version to compare commits against
55
+ * @returns {Promise<string>} The bump type: 'major', 'minor', or 'patch'
56
+ */
57
+ async getBumpType(cliArgs = {}, currentVersion) {
58
+ const argFromCli = cliArgs._[0];
59
+ if (argFromCli) {
60
+ return argFromCli;
61
+ }
62
+
63
+ // Getting all commits since last version tag
64
+ const rawCommits = await getGitDiff(
65
+ `v${currentVersion}`,
66
+ 'HEAD',
67
+ hostGitRoot(),
68
+ );
69
+ // This is the minimal object required by changelogen
70
+ const minimalConfig = { scopeMap: {} };
71
+ const commits = parseCommits(rawCommits, minimalConfig);
72
+
73
+ // If any commit has breaking changes: major
74
+ const hasBreakingChanges = _.some(commits, { isBreaking: true });
75
+ if (hasBreakingChanges) {
76
+ return 'major';
77
+ }
78
+
79
+ // If any commit adds a feature: minor
80
+ const hasFeature = _.some(commits, { type: 'feat' });
81
+ if (hasFeature) {
82
+ return 'minor';
83
+ }
84
+
85
+ // Anything else: patch
86
+ return 'patch';
87
+ },
88
+ };
89
+
90
+ /**
91
+ * Gathers all release information from CLI arguments
92
+ * @param {object} cliArgs - CLI arguments from minimist
93
+ * @returns {object} Release data containing bumpType, allPackages, currentVersion, newVersion, skipChangelog
94
+ */
95
+ export async function getReleaseData(cliArgs) {
96
+ const allPackages = await __.getAllPackagesToRelease();
97
+ const currentVersion = allPackages[0].content.version;
98
+
99
+ const bumpType = await __.getBumpType(cliArgs, currentVersion);
100
+
101
+ const newVersion = semver.inc(currentVersion, bumpType);
102
+ const skipChangelog = !!cliArgs['skip-changelog'];
103
+
104
+ return {
105
+ bumpType,
106
+ allPackages,
107
+ currentVersion,
108
+ newVersion,
109
+ skipChangelog,
110
+ };
111
+ }
package/lib/main.js ADDED
@@ -0,0 +1,52 @@
1
+ import path from 'node:path';
2
+ import { pMap } from 'golgoth';
3
+ import { consoleInfo, run as firostRun } from 'firost';
4
+ import { ensureValidSetup } from './ensureValidSetup.js';
5
+ import { getReleaseData } from './getReleaseData.js';
6
+ import { updateGitRepo } from './updateGitRepo.js';
7
+
8
+ export let __;
9
+
10
+ /**
11
+ * Wrapper to release the current module(s)
12
+ * @param {object} cliArgs CLI Argument object, as created by minimist
13
+ * @returns {boolean} True on success
14
+ */
15
+ export async function run(cliArgs = {}) {
16
+ await __.ensureValidSetup(cliArgs);
17
+
18
+ const releaseData = await __.getReleaseData(cliArgs);
19
+ __.consoleInfo(`Release new version ${releaseData.newVersion}`);
20
+
21
+ await __.updateGitRepo(releaseData);
22
+
23
+ await __.publishAllPackagesToNpm(releaseData);
24
+ }
25
+
26
+ __ = {
27
+ /**
28
+ * Publishes all packages to npm
29
+ * @param {object} releaseData - Release data containing allPackages
30
+ */
31
+ async publishAllPackagesToNpm(releaseData) {
32
+ await pMap(
33
+ releaseData.allPackages,
34
+ async ({ filepath, content }) => {
35
+ const packageName = content.name;
36
+ __.consoleInfo(`Publishing ${packageName} to npm`);
37
+
38
+ const packageDir = path.dirname(filepath);
39
+ await __.firostRun('npm publish --access public', { cwd: packageDir });
40
+ },
41
+ { concurrency: 1 },
42
+ );
43
+ },
44
+
45
+ ensureValidSetup,
46
+ updateGitRepo,
47
+ getReleaseData,
48
+ consoleInfo,
49
+ firostRun,
50
+ };
51
+
52
+ export default { run };
@@ -0,0 +1,150 @@
1
+ import { _ } from 'golgoth';
2
+ import {
3
+ consoleInfo,
4
+ exists,
5
+ firostError,
6
+ read,
7
+ run,
8
+ select,
9
+ write,
10
+ } from 'firost';
11
+ import { hostGitPath, hostGitRoot } from 'aberlaas-helper';
12
+ import { generateMarkDown, getGitDiff, parseCommits } from 'changelogen';
13
+ import cliMarkdown from 'cli-markdown';
14
+
15
+ export const __ = {
16
+ /**
17
+ * Generate changelog markdown from git commits between two versions
18
+ * @param {object} releaseData - Release data containing currentVersion, newVersion, and skipChangelog
19
+ * @returns {string} Generated changelog markdown
20
+ */
21
+ async generateChangelogFromGit(releaseData) {
22
+ const { currentVersion, newVersion } = releaseData;
23
+ const gitRoot = hostGitRoot();
24
+ const currentVersionTag = `v${currentVersion}`;
25
+
26
+ // Get config
27
+ const config = {
28
+ from: currentVersionTag,
29
+ to: 'HEAD',
30
+ newVersion,
31
+ noAuthors: true,
32
+ types: {
33
+ feat: { title: 'Features', semver: 'minor' },
34
+ fix: { title: 'Bug Fixes', semver: 'patch' },
35
+ perf: { title: 'Performance', semver: 'patch' },
36
+ },
37
+ templates: {
38
+ tagMessage: 'v{{newVersion}}',
39
+ tagBody: 'v{{newVersion}}',
40
+ },
41
+ // Note: This scopeMap key is required by changelogen
42
+ scopeMap: {},
43
+ };
44
+
45
+ const rawCommits = await getGitDiff(currentVersionTag, 'HEAD', gitRoot);
46
+ const commits = parseCommits(rawCommits, config);
47
+
48
+ // Filter commits to only keep user-facing types
49
+ const allowedTypes = _.keys(config.types);
50
+ const filteredCommits = _.filter(commits, (commit) => {
51
+ return _.includes(allowedTypes, commit.type);
52
+ });
53
+
54
+ // Sort commits by type order
55
+ const typeOrder = { feat: 0, fix: 1, perf: 2 };
56
+ const sortedCommits = _.sortBy(filteredCommits, (commit) => {
57
+ return typeOrder[commit.type];
58
+ });
59
+
60
+ // Generate markdown
61
+ return await generateMarkDown(sortedCommits, config);
62
+ },
63
+
64
+ /**
65
+ * Display the changelog and ask the user to accept/edit/cancel.
66
+ * @param {string} changelog - The changelog content to display and confirm
67
+ * @param {object} selectOptions - Options object with input stream for testing
68
+ * @returns {string} The approved (and possibly edited) changelog content
69
+ */
70
+ async confirmOrEditChangelog(changelog, selectOptions = {}) {
71
+ __.consoleInfo('CHANGELOG:');
72
+
73
+ __.consoleLog(_.repeat('━', 60));
74
+ __.consoleLog(__.cliMarkdown(changelog));
75
+ __.consoleLog(_.repeat('━', 60));
76
+
77
+ const nextStep = await __.select(
78
+ 'What to do?',
79
+ [
80
+ { name: '✅ Approve', value: 'approve' },
81
+ { name: '📝 Edit', value: 'edit' },
82
+ { name: '⛔️ Cancel', value: 'cancel' },
83
+ ],
84
+ selectOptions,
85
+ );
86
+
87
+ if (nextStep == 'cancel') {
88
+ throw firostError(
89
+ 'ABERLAAS_RELEASE_CHANGELOG_CANCELLED',
90
+ 'Release cancelled by user',
91
+ );
92
+ }
93
+
94
+ if (nextStep === 'approve') {
95
+ return changelog;
96
+ }
97
+
98
+ // Save the changelog in temp file and edit it
99
+ const changelogFilepath = hostGitPath('./tmp/CHANGELOG.md');
100
+ await write(changelog, changelogFilepath);
101
+
102
+ await __.run(`$EDITOR ${changelogFilepath}`, {
103
+ stdin: true,
104
+ shell: true,
105
+ });
106
+
107
+ const newChangelog = await read(changelogFilepath);
108
+ return await __.confirmOrEditChangelog(newChangelog, selectOptions);
109
+ },
110
+
111
+ /**
112
+ * Prepends new changelog content to existing CHANGELOG.md file
113
+ * @param {string} newChangelog - The new changelog content to prepend
114
+ */
115
+ async addToExistingChangelogFile(newChangelog) {
116
+ const changelogPath = hostGitPath('CHANGELOG.md');
117
+
118
+ if (!(await exists(changelogPath))) {
119
+ await write(newChangelog, changelogPath);
120
+ return;
121
+ }
122
+
123
+ const existingChangelog = await read(changelogPath);
124
+ const updatedChangelog = `${newChangelog}\n\n${existingChangelog}`;
125
+ await write(updatedChangelog, changelogPath);
126
+ },
127
+
128
+ consoleInfo,
129
+ consoleLog(input) {
130
+ console.log(input);
131
+ },
132
+ select,
133
+ cliMarkdown,
134
+ run,
135
+ };
136
+
137
+ /**
138
+ * Update the CHANGELOG.md file with new additions
139
+ * @param {object} releaseData - Release data containing currentVersion, newVersion, and skipChangelog
140
+ */
141
+ export async function updateChangelog(releaseData) {
142
+ if (releaseData.skipChangelog) {
143
+ return;
144
+ }
145
+
146
+ const suggestedChangelog = await __.generateChangelogFromGit(releaseData);
147
+ const approvedChangelog = await __.confirmOrEditChangelog(suggestedChangelog);
148
+
149
+ await __.addToExistingChangelogFile(approvedChangelog);
150
+ }
@@ -0,0 +1,62 @@
1
+ import { pMap } from 'golgoth';
2
+ import { consoleInfo, writeJson } from 'firost';
3
+ import { hostGitRoot } from 'aberlaas-helper';
4
+ import Gilmore from 'gilmore';
5
+ import { updateChangelog } from './updateChangelog.js';
6
+
7
+ export const __ = {
8
+ /**
9
+ * Bumps the version of all packages to the new version
10
+ * @param {object} releaseData - Release data containing allPackages and newVersion
11
+ */
12
+ async bumpAllPackageVersions(releaseData) {
13
+ await pMap(releaseData.allPackages, async ({ filepath, content }) => {
14
+ const packageName = content.name;
15
+ __.consoleInfo(`Updating ${packageName} to ${releaseData.newVersion}`);
16
+ const newContent = { ...content, version: releaseData.newVersion };
17
+ await writeJson(newContent, filepath, {
18
+ sort: false,
19
+ });
20
+ });
21
+ },
22
+
23
+ /**
24
+ * Creates a commit, tag, and pushes to remote repository
25
+ * @param {object} releaseData - Release data containing newVersion
26
+ */
27
+ async commitTagAndPush(releaseData) {
28
+ const gitRoot = hostGitRoot();
29
+ const repo = new Gilmore(gitRoot);
30
+
31
+ // Create commit
32
+ __.consoleInfo(
33
+ `Creating new commit for version v${releaseData.newVersion}`,
34
+ );
35
+ await repo.commitAll(`v${releaseData.newVersion}`, { skipHook: true });
36
+
37
+ // Create tag
38
+ await repo.createTag(`v${releaseData.newVersion}`);
39
+
40
+ // Push to remote
41
+ __.consoleInfo('Pushing to remote repository');
42
+ await repo.push();
43
+ },
44
+
45
+ consoleInfo,
46
+ updateChangelog,
47
+ };
48
+
49
+ /**
50
+ * Update git repository with all changes for the release
51
+ * @param {object} releaseData - Release data containing currentVersion, newVersion, skipChangelog, and allPackages
52
+ */
53
+ export async function updateGitRepo(releaseData) {
54
+ // Update CHANGELOG.md
55
+ await __.updateChangelog(releaseData);
56
+
57
+ // Update all .version keys in packages
58
+ await __.bumpAllPackageVersions(releaseData);
59
+
60
+ // Commit and push to remote
61
+ await __.commitTagAndPush(releaseData);
62
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "aberlaas-release",
3
+ "type": "module",
4
+ "sideEffects": false,
5
+ "description": "aberlaas release command: Release and publish new versions",
6
+ "version": "2.20.1",
7
+ "repository": "pixelastic/aberlaas",
8
+ "homepage": "https://projects.pixelastic.com/aberlaas/",
9
+ "author": "Tim Carry (@pixelastic)",
10
+ "license": "MIT",
11
+ "files": [
12
+ "lib/*.js"
13
+ ],
14
+ "exports": {
15
+ ".": "./lib/main.js"
16
+ },
17
+ "main": "./lib/main.js",
18
+ "engines": {
19
+ "node": ">=18.18.0"
20
+ },
21
+ "dependencies": {
22
+ "aberlaas-helper": "workspace:*",
23
+ "aberlaas-lint": "workspace:*",
24
+ "aberlaas-test": "workspace:*",
25
+ "changelogen": "0.6.2",
26
+ "cli-markdown": "3.5.1",
27
+ "firost": "5.5.1",
28
+ "gilmore": "1.2.0",
29
+ "golgoth": "3.0.0",
30
+ "semver": "7.7.3"
31
+ },
32
+ "scripts": {
33
+ "build": "cd ../docs && yarn run build",
34
+ "build:prod": "cd ../docs && yarn run build:prod",
35
+ "cms": "cd ../docs && yarn run cms",
36
+ "serve": "cd ../docs && yarn run serve",
37
+ "release": "cd ../.. && ./scripts/release",
38
+ "test:meta": "cd ../.. && ./scripts/test-meta",
39
+ "test": "cd ../.. && ./scripts/test",
40
+ "test:watch": "cd ../.. && ./scripts/test-watch",
41
+ "compress": "cd ../.. && ./scripts/compress",
42
+ "lint": "cd ../.. && ./scripts/lint",
43
+ "lint:fix": "cd ../.. && ./scripts/lint-fix"
44
+ }
45
+ }