changesets-gitlab
Version:
[](https://github.com/un-ts/changesets-gitlab/actions/workflows/ci.yml?query=branch%3Amain) [![CodeRabbit Pull Request Revie
202 lines (200 loc) • 8.82 kB
JavaScript
import fs from 'node:fs/promises';
import path from 'node:path';
import { exec } from '@actions/exec';
import { getPackages } from '@manypkg/get-packages';
import pLimit from 'p-limit';
import resolveFrom from 'resolve-from';
import semver from 'semver';
import { createApi } from "./api.js";
import * as context from './context.js';
import * as gitUtils from './git-utils.js';
import readChangesetState from './read-changeset-state.js';
import { cjsRequire, execWithOutput, getChangedPackages, getChangelogEntry, getOptionalInput, getVersionsByDirectory, GITLAB_MAX_TAGS, sortTheThings, } from './utils.js';
const limit = pLimit(2 * 3);
export const createRelease = async (api, { pkg, tagName }) => {
try {
const changelogFileName = path.join(pkg.dir, 'CHANGELOG.md');
const changelog = await fs.readFile(changelogFileName, 'utf8');
const changelogEntry = getChangelogEntry(changelog, pkg.packageJson.version);
if (!changelogEntry) {
throw new Error(`Could not find changelog entry for ${pkg.packageJson.name}@${pkg.packageJson.version}`);
}
await api.ProjectReleases.create(context.projectId, {
name: tagName,
tag_name: tagName,
description: changelogEntry.content,
pre_release: pkg.packageJson.version.includes('-'),
});
}
catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
};
export async function runPublish({ script, gitlabToken, createGitlabReleases = true, cwd = process.cwd(), }) {
const api = createApi(gitlabToken);
const [publishCommand, ...publishArgs] = script.split(/\s+/);
const changesetPublishOutput = await execWithOutput(publishCommand, publishArgs, { cwd });
const { packages, tool } = await getPackages(cwd);
const pushAllTags = packages.length <= GITLAB_MAX_TAGS ||
(await api.FeatureFlags.show(context.projectId, 'git_push_create_all_pipelines')
.then(({ active }) => active)
.catch(() => false));
if (pushAllTags) {
await gitUtils.pushTags();
}
const releasedPackages = [];
if (tool === 'root') {
if (packages.length !== 1) {
throw new Error(`No package found.` +
'This is probably a bug in the action, please open an issue');
}
const pkg = packages[0];
const newTagRegex = /New tag:/;
for (const line of changesetPublishOutput.stdout.split('\n')) {
const match = newTagRegex.exec(line);
if (match) {
releasedPackages.push(pkg);
const tagName = `v${pkg.packageJson.version}`;
if (createGitlabReleases) {
await createRelease(api, { pkg, tagName });
}
break;
}
}
}
else {
const newTagRegex = /New tag:\s+(@[^/]+\/[^@]+|[^/]+)@(\S+)/;
const packagesByName = new Map(packages.map(x => [x.packageJson.name, x]));
for (const line of changesetPublishOutput.stdout.split('\n')) {
const match = newTagRegex.exec(line);
if (match === null) {
continue;
}
const pkgName = match[1];
const pkg = packagesByName.get(pkgName);
if (pkg === undefined) {
throw new Error(`Package "${pkgName}" not found.` +
'This is probably a bug in the action, please open an issue');
}
releasedPackages.push(pkg);
}
if (!pushAllTags) {
await Promise.all(releasedPackages.map(pkg => gitUtils.pushTag(`${pkg.packageJson.name}@${pkg.packageJson.version}`)));
}
if (createGitlabReleases) {
await Promise.all(releasedPackages.map(pkg => limit(() => createRelease(api, {
pkg,
tagName: `${pkg.packageJson.name}@${pkg.packageJson.version}`,
}))));
}
}
if (releasedPackages.length > 0) {
return {
published: true,
publishedPackages: releasedPackages.map(pkg => ({
name: pkg.packageJson.name,
version: pkg.packageJson.version,
})),
};
}
return { published: false };
}
const requireChangesetsCliPkgJson = (cwd) => {
try {
return cjsRequire(resolveFrom(cwd, '@changesets/cli/package.json'));
}
catch (err) {
if (err?.code === 'MODULE_NOT_FOUND') {
throw new Error(`Have you forgotten to install \`@changesets/cli\` in "${cwd}"?`);
}
throw err;
}
};
export async function runVersion({ script, gitlabToken, cwd = process.cwd(), mrTitle = 'Version Packages', mrTargetBranch = context.ref, commitMessage = 'Version Packages', removeSourceBranch = false, hasPublishScript = false, }) {
const currentBranch = context.ref;
const versionBranch = `changeset-release/${currentBranch}`;
const api = createApi(gitlabToken);
const { preState } = await readChangesetState(cwd);
await gitUtils.switchToMaybeExistingBranch(versionBranch);
await exec('git', ['fetch', 'origin', currentBranch]);
await gitUtils.reset(`origin/${currentBranch}`);
const labels = getOptionalInput('labels')
?.split(',')
.map(x => x.trim());
const versionsByDirectory = await getVersionsByDirectory(cwd);
if (script) {
const [versionCommand, ...versionArgs] = script.split(/\s+/);
await exec(versionCommand, versionArgs, { cwd });
}
else {
const changesetsCliPkgJson = requireChangesetsCliPkgJson(cwd);
const cmd = semver.lt(changesetsCliPkgJson.version, '2.0.0')
? 'bump'
: 'version';
await exec('node', [resolveFrom(cwd, '@changesets/cli/bin.js'), cmd], {
cwd,
});
}
const changedPackages = await getChangedPackages(cwd, versionsByDirectory);
const mrBodyPromise = (async () => `This MR was opened by the [changesets-gitlab](https://github.com/un-ts/changesets-gitlab) GitLab CI script. When you're ready to do a release, you can merge this and ${hasPublishScript
? 'the packages will be published to npm automatically'
: 'publish to npm yourself or [setup this action to publish automatically](https://github.com/un-ts/changesets-gitlab#with-publishing)'}. If you're not ready to do a release yet, that's fine, whenever you add more changesets to ${currentBranch}, this MR will be updated.
${preState
? `
⚠️⚠️⚠️⚠️⚠️⚠️
\`${currentBranch}\` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run \`changeset pre exit\` on \`${currentBranch}\`.
⚠️⚠️⚠️⚠️⚠️⚠️
`
: ''}
# Releases
` +
(await Promise.all(changedPackages.map(async (pkg) => {
const changelogContents = await fs.readFile(path.join(pkg.dir, 'CHANGELOG.md'), 'utf8');
const entry = getChangelogEntry(changelogContents, pkg.packageJson.version);
return {
highestLevel: entry.highestLevel,
private: !!pkg.packageJson.private,
content: `## ${pkg.packageJson.name}@${pkg.packageJson.version}\n\n` +
entry.content,
};
})))
.filter(Boolean)
.sort(sortTheThings)
.map(x => x.content)
.join('\n '))();
const finalMrTitle = `${mrTitle}${preState ? ` (${preState.tag})` : ''}`;
if (!(await gitUtils.checkIfClean())) {
const finalCommitMessage = `${commitMessage}${preState ? ` (${preState.tag})` : ''}`;
await gitUtils.commitAll(finalCommitMessage);
}
await gitUtils.push(versionBranch, { force: true });
const searchResult = await api.MergeRequests.all({
projectId: context.projectId,
state: 'opened',
sourceBranch: versionBranch,
target_branch: mrTargetBranch,
maxPages: 1,
perPage: 1,
});
console.log(JSON.stringify(searchResult, null, 2));
if (searchResult.length === 0) {
console.log(`creating merge request from ${versionBranch} to ${mrTargetBranch}.`);
await api.MergeRequests.create(context.projectId, versionBranch, mrTargetBranch, finalMrTitle, {
description: await mrBodyPromise,
removeSourceBranch,
labels,
});
}
else {
console.log(`updating found merge request !${searchResult[0].iid}`);
await api.MergeRequests.edit(context.projectId, searchResult[0].iid, {
title: finalMrTitle,
description: await mrBodyPromise,
removeSourceBranch,
labels,
});
}
}
//# sourceMappingURL=run.js.map