changesets-gitlab
Version:
[](https://github.com/un-ts/changesets-gitlab/actions/workflows/ci.yml?query=branch%3Amain) [![CodeRabbit Pull Request Revie
1,177 lines (1,141 loc) • 40.3 kB
JavaScript
;
var rest = require('@gitbeaker/rest');
var globalAgent = require('global-agent');
var core = require('@actions/core');
var dotenv = require('dotenv');
var errors = require('@changesets/errors');
var humanId = require('human-id');
var markdownTable = require('markdown-table');
var fs$1 = require('node:fs/promises');
var path = require('node:path');
var assembleReleasePlan = require('@changesets/assemble-release-plan');
var config = require('@changesets/config');
var parseChangeset = require('@changesets/parse');
var micromatch = require('micromatch');
var yaml = require('yaml');
var node_child_process = require('node:child_process');
var fs = require('node:fs');
var node_module = require('node:module');
var exec = require('@actions/exec');
var getPackages = require('@manypkg/get-packages');
var mdastUtilToString = require('mdast-util-to-string');
var remarkParse = require('remark-parse');
var remarkStringify = require('remark-stringify');
var unified = require('unified');
var node_url = require('node:url');
var pre = require('@changesets/pre');
var readChangesets = require('@changesets/read');
var pLimit = require('p-limit');
var resolveFrom = require('resolve-from');
var semver = require('semver');
var __defProp$2 = Object.defineProperty;
var __defProps$1 = Object.defineProperties;
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$2 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
if (__getOwnPropSymbols$2)
for (var prop of __getOwnPropSymbols$2(b)) {
if (__propIsEnum$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
}
return a;
};
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
var _a$1, _b, _c;
dotenv.config();
let isGitlabTokenValidated = false;
const env = __spreadProps$1(__spreadValues$2({}, process.env), {
CI_MERGE_REQUEST_IID: +process.env.CI_MERGE_REQUEST_IID,
GITLAB_HOST: (_b = (_a$1 = process.env.GITLAB_HOST) != null ? _a$1 : process.env.CI_SERVER_URL) != null ? _b : "https://gitlab.com",
GITLAB_CI_USER_EMAIL: process.env.GITLAB_CI_USER_EMAIL || "gitlab[bot]@users.noreply.gitlab.com",
GITLAB_COMMENT_TYPE: (_c = process.env.GITLAB_COMMENT_TYPE) != null ? _c : "discussion",
// only check for the token if we are explicitly using it
get GITLAB_TOKEN() {
if (!isGitlabTokenValidated) {
isGitlabTokenValidated = true;
if (!process.env.GITLAB_TOKEN) {
core.setFailed("Please add the `GITLAB_TOKEN` to the changesets action");
}
}
return process.env.GITLAB_TOKEN;
}
});
const PROXY_PROPS = ["http_proxy", "https_proxy", "no_proxy"];
let bootstrapped = false;
const createApi = (gitlabToken) => {
if (!bootstrapped) {
bootstrapped = true;
globalAgent.bootstrap();
for (const prop of PROXY_PROPS) {
const uProp = prop.toUpperCase();
const value = process.env[uProp] || process.env[prop];
if (value) {
GLOBAL_AGENT[uProp] = value;
}
}
}
const token = gitlabToken || env.GITLAB_TOKEN;
const host = env.GITLAB_HOST;
if (env.GITLAB_TOKEN_TYPE === "oauth") {
return new rest.Gitlab({
host,
oauthToken: token
});
}
return new rest.Gitlab({
host,
token
});
};
const projectId = process.env.CI_PROJECT_ID;
const ref = process.env.CI_COMMIT_REF_NAME;
var __defProp$1 = Object.defineProperty;
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$1 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
if (__getOwnPropSymbols$1)
for (var prop of __getOwnPropSymbols$1(b)) {
if (__propIsEnum$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
}
return a;
};
var __async$6 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
const import_meta = {};
const BumpLevels = {
dep: 0,
patch: 1,
minor: 2,
major: 3
};
function getVersionsByDirectory(cwd) {
return __async$6(this, null, function* () {
const { packages } = yield getPackages.getPackages(cwd);
return new Map(packages.map((x) => [x.dir, x.packageJson.version]));
});
}
function getChangedPackages$1(cwd, previousVersions) {
return __async$6(this, null, function* () {
const { packages } = yield getPackages.getPackages(cwd);
const changedPackages = /* @__PURE__ */ new Set();
for (const pkg of packages) {
const previousVersion = previousVersions.get(pkg.dir);
if (previousVersion !== pkg.packageJson.version) {
changedPackages.add(pkg);
}
}
return [...changedPackages];
});
}
function getChangelogEntry(changelog, version) {
const ast = unified.unified().use(remarkParse).parse(changelog);
let highestLevel = BumpLevels.dep;
const nodes = ast.children;
let headingStartInfo;
let endIndex;
for (const [i, node] of nodes.entries()) {
if (node.type === "heading") {
const stringified = mdastUtilToString.toString(node);
const match = /(major|minor|patch)/.exec(stringified.toLowerCase());
if (match !== null) {
const level = BumpLevels[match[0]];
highestLevel = Math.max(level, highestLevel);
}
if (headingStartInfo === void 0 && stringified === version) {
headingStartInfo = {
index: i,
depth: node.depth
};
continue;
}
if (endIndex === void 0 && headingStartInfo !== void 0 && headingStartInfo.depth === node.depth) {
endIndex = i;
break;
}
}
}
if (headingStartInfo) {
ast.children = ast.children.slice(
headingStartInfo.index + 1,
// eslint-disable-next-line sonarjs/argument-type
endIndex
);
}
return {
content: unified.unified().use(remarkStringify).stringify(ast),
highestLevel
};
}
function execWithOutput(command, args, options) {
return __async$6(this, null, function* () {
let myOutput = "";
let myError = "";
return {
code: yield exec.exec(command, args, __spreadValues$1({
listeners: {
stdout: (data) => {
myOutput += data.toString();
},
stderr: (data) => {
myError += data.toString();
}
}
}, options)),
stdout: myOutput,
stderr: myError
};
});
}
function sortTheThings(a, b) {
if (a.private === b.private) {
return b.highestLevel - a.highestLevel;
}
if (a.private) {
return 1;
}
return -1;
}
const identify = (_) => !!_;
function getAllFiles(_0) {
return __async$6(this, arguments, function* (dir, base = dir) {
const direntList = yield fs.promises.readdir(dir, { withFileTypes: true });
const files = yield Promise.all(
// eslint-disable-next-line sonarjs/function-return-type
direntList.map((dirent) => {
const res = path.resolve(dir, dirent.name);
return dirent.isDirectory() ? getAllFiles(res, base) : [path.relative(base, res)];
})
);
return files.flat();
});
}
const execSync = (command) => (
// eslint-disable-next-line sonarjs/os-command
node_child_process.execSync(command, { stdio: "inherit" })
);
const getOptionalInput = (name) => core.getInput(name) || void 0;
const getUsername = (api) => {
var _a;
return (_a = env.GITLAB_CI_USER_NAME) != null ? _a : api.Users.showCurrentUser().then((currentUser) => currentUser.username);
};
const cjsRequire = typeof require === "undefined" ? node_module.createRequire(import_meta.url) : require;
const FALSY_VALUES = /* @__PURE__ */ new Set(["false", "0"]);
const TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "1"]);
const GITLAB_MAX_TAGS = 4;
const HTTP_STATUS_NOT_FOUND = 404;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __async$5 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
function fetchFile(path) {
return fs$1.readFile(path, "utf8");
}
const getChangedPackages = (_0) => __async$5(void 0, [_0], function* ({
changedFiles: changedFilesPromise
}) {
var _a;
let hasErrored = false;
function fetchJsonFile(path) {
return __async$5(this, null, function* () {
try {
const x = yield fetchFile(path);
return JSON.parse(x);
} catch (err) {
hasErrored = true;
console.error(err);
return {};
}
});
}
function fetchTextFile(path) {
return __async$5(this, null, function* () {
try {
return yield fetchFile(path);
} catch (err) {
hasErrored = true;
console.error(err);
return "";
}
});
}
function getPackage(pkgPath) {
return __async$5(this, null, function* () {
const jsonContent = yield fetchJsonFile(
pkgPath + "/package.json"
);
return {
packageJson: jsonContent,
dir: pkgPath
};
});
}
const rootPackageJsonContentsPromise = fetchJsonFile("package.json");
const configPromise = fetchJsonFile(".changeset/config.json");
const tree = yield getAllFiles(process.cwd());
let preStatePromise;
const changesetPromises = [];
const potentialWorkspaceDirectories = [];
let isPnpm = false;
const changedFiles = yield changedFilesPromise;
for (const item of tree) {
if (item.endsWith("/package.json")) {
const dirPath = path.dirname(item);
potentialWorkspaceDirectories.push(dirPath);
} else if (item === "pnpm-workspace.yaml") {
isPnpm = true;
} else if (item === ".changeset/pre.json") {
preStatePromise = fetchJsonFile(".changeset/pre.json");
} else if (item !== ".changeset/README.md" && item.startsWith(".changeset") && item.endsWith(".md") && changedFiles.includes(item)) {
const res = /\.changeset\/([^.]+)\.md/.exec(item);
if (!res) {
throw new Error("could not get name from changeset filename");
}
const id = res[1];
changesetPromises.push(
fetchTextFile(item).then((text) => __spreadProps(__spreadValues({}, parseChangeset(text)), {
id
}))
);
}
}
let tool;
if (isPnpm) {
tool = {
tool: "pnpm",
globs: yaml.parse(yield fetchTextFile("pnpm-workspace.yaml")).packages
};
} else {
const rootPackageJsonContent2 = yield rootPackageJsonContentsPromise;
if (rootPackageJsonContent2.workspaces) {
tool = {
tool: "yarn",
globs: Array.isArray(rootPackageJsonContent2.workspaces) ? rootPackageJsonContent2.workspaces : rootPackageJsonContent2.workspaces.packages
};
} else if ((_a = rootPackageJsonContent2.bolt) == null ? void 0 : _a.workspaces) {
tool = {
tool: "bolt",
globs: rootPackageJsonContent2.bolt.workspaces
};
}
}
const rootPackageJsonContent = yield rootPackageJsonContentsPromise;
const packages = {
root: {
dir: "/",
packageJson: rootPackageJsonContent
},
tool: tool ? tool.tool : "root",
packages: []
};
if (tool) {
if (!Array.isArray(tool.globs) || !tool.globs.every((x) => typeof x === "string")) {
throw new Error("globs are not valid: " + JSON.stringify(tool.globs));
}
const matches = micromatch(potentialWorkspaceDirectories, tool.globs);
packages.packages = yield Promise.all(matches.map((dir) => getPackage(dir)));
} else {
packages.packages.push(packages.root);
}
if (hasErrored) {
throw new Error("an error occurred when fetching files");
}
const config$1 = yield configPromise.then(
(rawConfig) => config.parse(rawConfig, packages)
);
const releasePlan = assembleReleasePlan(
yield Promise.all(changesetPromises),
packages,
config$1,
yield preStatePromise
);
return {
changedPackages: (packages.tool === "root" ? packages.packages : packages.packages.filter(
(pkg) => changedFiles.some((changedFile) => changedFile.includes(pkg.dir))
)).filter(
(pkg) => pkg.packageJson.private !== true && !config$1.ignore.includes(pkg.packageJson.name)
).map((x) => x.packageJson.name),
releasePlan
};
});
var __async$4 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
var _a;
const generatedByBotNote = "Generated By Changesets GitLab Bot";
const getReleasePlanMessage = (releasePlan) => {
if (!releasePlan) {
return "";
}
const publishableReleases = releasePlan.releases.filter(
(x) => x.type !== "none"
);
const table = markdownTable.markdownTable([
["Name", "Type"],
...publishableReleases.map((x) => [
x.name,
{
major: "Major",
minor: "Minor",
patch: "Patch"
}[x.type]
])
]);
return `<details><summary>This MR includes ${releasePlan.changesets.length > 0 ? `changesets to release ${// eslint-disable-next-line sonarjs/no-nested-conditional
publishableReleases.length === 1 ? "1 package" : `${publishableReleases.length} packages`}` : "no changesets"}</summary>
${publishableReleases.length > 0 ? table : "When changesets are added to this MR, you'll see the packages that this MR includes changesets for and the associated semver types"}
</details>`;
};
const customLinks = (_a = env.GITLAB_COMMENT_CUSTOM_LINKS) == null ? void 0 : _a.trim();
const ADD_CHANGESET_URL_PLACEHOLDER_REGEXP = /\{\{\s*addChangesetUrl\s*\}\}/;
const getAbsentMessage = (commitSha, addChangesetUrl, newChangesetTemplateFallback, releasePlan) => `### \u26A0\uFE0F No Changeset found
Latest commit: ${commitSha}
Merging this MR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**
${getReleasePlanMessage(releasePlan)}
${customLinks ? customLinks.replace(ADD_CHANGESET_URL_PLACEHOLDER_REGEXP, addChangesetUrl) : `[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).
[Click here if you're a maintainer who wants to add a changeset to this MR](${addChangesetUrl})`}
${newChangesetTemplateFallback}
__${generatedByBotNote}__
`;
const getApproveMessage = (commitSha, addChangesetUrl, newChangesetTemplateFallback, releasePlan) => `### \u{1F98B} Changeset detected
Latest commit: ${commitSha}
**The changes in this MR will be included in the next version bump.**
${getReleasePlanMessage(releasePlan)}
${customLinks ? customLinks.replace(ADD_CHANGESET_URL_PLACEHOLDER_REGEXP, addChangesetUrl) : `Not sure what this means? [Click here to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).
[Click here if you're a maintainer who wants to add another changeset to this MR](${addChangesetUrl})`}
${newChangesetTemplateFallback}
__${generatedByBotNote}__
`;
const getNewChangesetTemplate = (changedPackages, title) => `---
${changedPackages.map((x) => `"${x}": patch`).join("\n")}
---
${title}
`;
const isMrNote = (discussionOrNote) => "noteable_type" in discussionOrNote && discussionOrNote.noteable_type === "MergeRequest";
const RANDOM_BOT_NAME_PATTERN = /^((?:project|group)_\d+_bot\w*)_[\da-z]+$/i;
const isChangesetBotNote = (note, username, random) => {
var _a2;
return (note.author.username === username || random && ((_a2 = RANDOM_BOT_NAME_PATTERN.exec(note.author.username)) == null ? void 0 : _a2[1]) === username) && // We need to ensure the note is generated by us, but we don't have an app bot like GitHub
// @see https://github.com/apps/changeset-bot
note.body.includes(generatedByBotNote);
};
function getNoteInfo(api, mrIid, commentType, random) {
return __async$4(this, null, function* () {
const discussionOrNotes = yield commentType === "discussion" ? api.MergeRequestDiscussions.all(projectId, mrIid) : api.MergeRequestNotes.all(projectId, +mrIid);
const username = yield getUsername(api);
for (const discussionOrNote of discussionOrNotes) {
if (isMrNote(discussionOrNote)) {
if (isChangesetBotNote(discussionOrNote, username, random)) {
return {
noteId: discussionOrNote.id
};
}
continue;
}
if (!discussionOrNote.notes) {
continue;
}
const changesetBotNote = discussionOrNote.notes.find(
(note) => isChangesetBotNote(note, username)
);
if (changesetBotNote) {
return {
discussionId: discussionOrNote.id,
noteId: changesetBotNote.id
};
}
}
return random ? null : getNoteInfo(api, mrIid, commentType, true);
});
}
const hasChangesetBeenAdded = (changedFilesPromise) => __async$4(void 0, null, function* () {
const changedFiles = yield changedFilesPromise;
return changedFiles.some((file) => {
return file.new_file && /^\.changeset\/.+\.md$/.test(file.new_path) && file.new_path !== ".changeset/README.md";
});
});
const comment = () => __async$4(void 0, null, function* () {
const mrBranch = env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME;
if (!mrBranch) {
console.warn("[changesets-gitlab:comment] It should only be used on MR");
return;
}
const {
CI_MERGE_REQUEST_IID: mrIid,
GITLAB_COMMENT_TYPE: commentType,
GITLAB_ADD_CHANGESET_MESSAGE: commitMessage
} = env;
if (mrBranch.startsWith("changeset-release")) {
return;
}
const api = createApi();
let errFromFetchingChangedFiles = "";
try {
const latestCommitSha = env.CI_MERGE_REQUEST_SOURCE_BRANCH_SHA;
const changedFilesPromise = api.MergeRequests.allDiffs(
projectId,
mrIid
).catch((err) => __async$4(void 0, null, function* () {
var _a2;
if (!(err instanceof rest.GitbeakerRequestError) || ((_a2 = err.cause) == null ? void 0 : _a2.response.status) !== HTTP_STATUS_NOT_FOUND) {
throw err;
}
const { changes } = yield api.MergeRequests.showChanges(
projectId,
mrIid
);
return changes;
}));
const [noteInfo, hasChangeset, { changedPackages, releasePlan }] = yield Promise.all([
getNoteInfo(api, mrIid, commentType),
hasChangesetBeenAdded(changedFilesPromise),
getChangedPackages({
changedFiles: changedFilesPromise.then(
(changedFiles) => changedFiles.map(({ new_path }) => new_path)
),
api
}).catch((err) => {
if (err instanceof errors.ValidationError) {
errFromFetchingChangedFiles = `<details><summary>\u{1F4A5} An error occurred when fetching the changed packages and changesets in this MR</summary>
\`\`\`
${err.message}
\`\`\`
</details>
`;
} else {
console.error(err);
}
return {
changedPackages: ["@fake-scope/fake-pkg"],
releasePlan: null
};
})
]);
const newChangesetFileName = `.changeset/${humanId.humanId({
separator: "-",
capitalize: false
})}.md`;
const newChangesetTemplate = getNewChangesetTemplate(
changedPackages,
env.CI_MERGE_REQUEST_TITLE
);
const addChangesetUrl = `${env.CI_MERGE_REQUEST_PROJECT_URL}/-/new/${mrBranch}?file_name=${newChangesetFileName}&file=${encodeURIComponent(newChangesetTemplate)}${commitMessage ? "&commit_message=" + encodeURIComponent(commitMessage) : ""}`;
const newChangesetTemplateFallback = `
If the above link doesn't fill the changeset template file name and content which is [a known regression on GitLab >= 16.11](https://gitlab.com/gitlab-org/gitlab/-/issues/532221), you can copy and paste the following template into ${newChangesetFileName} instead:
\`\`\`yaml
${newChangesetTemplate}
\`\`\`
`.trim();
const prComment = (hasChangeset ? getApproveMessage(
latestCommitSha,
addChangesetUrl,
newChangesetTemplateFallback,
releasePlan
) : getAbsentMessage(
latestCommitSha,
addChangesetUrl,
newChangesetTemplateFallback,
releasePlan
)) + errFromFetchingChangedFiles;
switch (commentType) {
case "discussion": {
if (noteInfo) {
if (hasChangeset && TRUTHY_VALUES.has(env.GITLAB_COMMENT_DISCUSSION_AUTO_RESOLVE || "1")) {
yield api.MergeRequestDiscussions.resolve(
projectId,
mrIid,
noteInfo.discussionId,
true
);
}
return api.MergeRequestDiscussions.editNote(
projectId,
mrIid,
noteInfo.discussionId,
noteInfo.noteId,
{
body: prComment
}
);
}
return api.MergeRequestDiscussions.create(
projectId,
mrIid,
prComment
);
}
case "note": {
if (noteInfo) {
return api.MergeRequestNotes.edit(
projectId,
mrIid,
noteInfo.noteId,
{ body: prComment }
);
}
return api.MergeRequestNotes.create(projectId, mrIid, prComment);
}
default: {
throw new Error(
`Invalid comment type "${commentType}", should be "discussion" or "note"`
);
}
}
} catch (err) {
if (err instanceof rest.GitbeakerRequestError && err.cause) {
const { description, request, response } = err.cause;
console.error(description);
try {
console.error("request:", yield request.text());
} catch (e) {
console.error("The error's request could not be used as plain text");
}
try {
console.error("response:", yield response.text());
} catch (e) {
console.error("The error's response could not be used as plain text");
}
}
throw err;
}
});
var __async$3 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
const setupUser = () => __async$3(void 0, null, function* () {
yield exec.exec("git", [
"config",
"user.name",
env.GITLAB_CI_USER_NAME || env.GITLAB_USER_NAME
]);
yield exec.exec("git", ["config", "user.email", env.GITLAB_CI_USER_EMAIL]);
});
const push = (_0, ..._1) => __async$3(void 0, [_0, ..._1], function* (branch, { force } = {}) {
yield exec.exec(
"git",
["push", "origin", `HEAD:${branch}`, force && "--force"].filter(identify)
);
});
const pushTags = () => __async$3(void 0, null, function* () {
yield exec.exec("git", ["push", "origin", "--tags"]);
});
const pushTag = (tag) => __async$3(void 0, null, function* () {
yield exec.exec("git", ["push", "origin", tag]);
});
const switchToMaybeExistingBranch = (branch) => __async$3(void 0, null, function* () {
const { stderr } = yield execWithOutput("git", ["checkout", branch], {
ignoreReturnCode: true
});
const isCreatingBranch = !stderr.includes(`Switched to branch '${branch}'`) && // it could be a detached HEAD
!stderr.includes(`Switched to a new branch '${branch}'`);
if (isCreatingBranch) {
yield exec.exec("git", ["checkout", "-b", branch]);
}
});
const reset = (pathSpec, mode = "hard") => __async$3(void 0, null, function* () {
yield exec.exec("git", ["reset", `--${mode}`, pathSpec]);
});
const commitAll = (message) => __async$3(void 0, null, function* () {
yield exec.exec("git", ["add", "-A", "."]);
yield exec.exec("git", ["commit", "-m", message]);
});
const checkIfClean = () => __async$3(void 0, null, function* () {
const { stdout } = yield execWithOutput("git", ["status", "--porcelain"]);
return stdout.length === 0;
});
var __async$2 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
function readChangesetState() {
return __async$2(this, arguments, function* (cwd = process.cwd()) {
const preState = yield pre.readPreState(cwd);
const isInPreMode = preState !== void 0 && preState.mode === "pre";
let changesets = yield readChangesets(cwd);
if (isInPreMode) {
const changesetsToFilter = new Set(preState.changesets);
changesets = changesets.filter((x) => !changesetsToFilter.has(x.id));
}
return {
preState: isInPreMode ? preState : void 0,
changesets
};
});
}
var __async$1 = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
const limit = pLimit(2 * 3);
const createRelease = (_0, _1) => __async$1(void 0, [_0, _1], function* (api, { pkg, tagName }) {
try {
const changelogFileName = path.join(pkg.dir, "CHANGELOG.md");
const changelog = yield fs$1.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}`
);
}
yield api.ProjectReleases.create(projectId, {
name: tagName,
tag_name: tagName,
description: changelogEntry.content,
pre_release: pkg.packageJson.version.includes("-")
});
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
});
function runPublish(_0) {
return __async$1(this, arguments, function* ({
script,
gitlabToken,
createGitlabReleases = true,
cwd = process.cwd()
}) {
const api = createApi(gitlabToken);
const [publishCommand, ...publishArgs] = script.split(/\s+/);
const changesetPublishOutput = yield execWithOutput(
publishCommand,
publishArgs,
{ cwd }
);
const { packages, tool } = yield getPackages.getPackages(cwd);
const pushAllTags = packages.length <= GITLAB_MAX_TAGS || (yield api.FeatureFlags.show(
projectId,
"git_push_create_all_pipelines"
).then(({ active }) => active).catch(() => false));
if (pushAllTags) {
yield 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) {
yield 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 === void 0) {
throw new Error(
`Package "${pkgName}" not found.This is probably a bug in the action, please open an issue`
);
}
releasedPackages.push(pkg);
}
if (!pushAllTags) {
yield Promise.all(
releasedPackages.map(
(pkg) => pushTag(
`${pkg.packageJson.name}@${pkg.packageJson.version}`
)
)
);
}
if (createGitlabReleases) {
yield 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 == null ? void 0 : err.code) === "MODULE_NOT_FOUND") {
throw new Error(
`Have you forgotten to install \`@changesets/cli\` in "${cwd}"?`
);
}
throw err;
}
};
function runVersion(_0) {
return __async$1(this, arguments, function* ({
script,
gitlabToken,
cwd = process.cwd(),
mrTitle = "Version Packages",
mrTargetBranch = ref,
commitMessage = "Version Packages",
removeSourceBranch = false,
hasPublishScript = false
}) {
var _a;
const currentBranch = ref;
const versionBranch = `changeset-release/${currentBranch}`;
const api = createApi(gitlabToken);
const { preState } = yield readChangesetState(cwd);
yield switchToMaybeExistingBranch(versionBranch);
yield exec.exec("git", ["fetch", "origin", currentBranch]);
yield reset(`origin/${currentBranch}`);
const labels = (_a = getOptionalInput("labels")) == null ? void 0 : _a.split(",").map((x) => x.trim());
const versionsByDirectory = yield getVersionsByDirectory(cwd);
if (script) {
const [versionCommand, ...versionArgs] = script.split(/\s+/);
yield exec.exec(versionCommand, versionArgs, { cwd });
} else {
const changesetsCliPkgJson = requireChangesetsCliPkgJson(cwd);
const cmd = semver.lt(changesetsCliPkgJson.version, "2.0.0") ? "bump" : "version";
yield exec.exec("node", [resolveFrom(cwd, "@changesets/cli/bin.js"), cmd], {
cwd
});
}
const changedPackages = yield getChangedPackages$1(cwd, versionsByDirectory);
const mrBodyPromise = (() => __async$1(this, null, function* () {
return `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 ? `
\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F
\`${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}\`.
\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F\u26A0\uFE0F
` : ""}
# Releases
` + (yield Promise.all(
changedPackages.map((pkg) => __async$1(this, null, function* () {
const changelogContents = yield fs$1.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}
` + entry.content
};
}))
)).filter(Boolean).sort(sortTheThings).map((x) => x.content).join("\n ");
}))();
const finalMrTitle = `${mrTitle}${preState ? ` (${preState.tag})` : ""}`;
if (!(yield checkIfClean())) {
const finalCommitMessage = `${commitMessage}${preState ? ` (${preState.tag})` : ""}`;
yield commitAll(finalCommitMessage);
}
yield push(versionBranch, { force: true });
const searchResult = yield api.MergeRequests.all({
projectId: 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}.`
);
yield api.MergeRequests.create(
projectId,
versionBranch,
mrTargetBranch,
finalMrTitle,
{
description: yield mrBodyPromise,
removeSourceBranch,
labels
}
);
} else {
console.log(`updating found merge request !${searchResult[0].iid}`);
yield api.MergeRequests.edit(projectId, searchResult[0].iid, {
title: finalMrTitle,
description: yield mrBodyPromise,
removeSourceBranch,
labels
});
}
});
}
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
const main = (..._0) => __async(void 0, [..._0], function* ({
published,
onlyChangesets
} = {}) {
const { GITLAB_TOKEN, NPM_TOKEN } = env;
core.setOutput("published", false);
core.setOutput("publishedPackages", []);
if (env.CI) {
console.log("setting git user");
yield setupUser();
const url = new node_url.URL(env.GITLAB_HOST);
console.log("setting GitLab credentials");
const username = yield getUsername(createApi());
yield exec.exec(
"git",
[
"remote",
"set-url",
"origin",
`${url.protocol}//${encodeURIComponent(username)}:${GITLAB_TOKEN}@${url.host}${url.pathname.replace(/\/$/, "")}/${env.CI_PROJECT_PATH}.git`
],
{ silent: !TRUTHY_VALUES.has(env.DEBUG_GITLAB_CREDENTIAL) }
);
}
const { changesets } = yield readChangesetState();
const publishScript = core.getInput("publish");
const hasChangesets = changesets.length > 0;
const hasPublishScript = !!publishScript;
switch (true) {
case (!hasChangesets && !hasPublishScript): {
console.log("No changesets found");
return;
}
case (!hasChangesets && hasPublishScript): {
console.log(
"No changesets found, attempting to publish any unpublished packages to npm"
);
const npmrcPath = `${env.HOME}/.npmrc`;
if (fs.existsSync(npmrcPath)) {
console.log("Found existing .npmrc file");
} else if (NPM_TOKEN) {
console.log("No .npmrc file found, creating one");
yield fs.promises.writeFile(
npmrcPath,
`//registry.npmjs.org/:_authToken=${NPM_TOKEN}`
);
} else {
core.setFailed(
"No `.npmrc` found nor `NPM_TOKEN` provided, unable to publish packages"
);
return;
}
const result = yield runPublish({
script: publishScript,
gitlabToken: GITLAB_TOKEN,
createGitlabReleases: !FALSY_VALUES.has(
core.getInput("create_gitlab_releases")
)
});
if (result.published) {
core.setOutput("published", true);
core.setOutput("publishedPackages", result.publishedPackages);
core.exportVariable("PUBLISHED", true);
core.exportVariable("PUBLISHED_PACKAGES", result.publishedPackages);
if (published) {
execSync(published);
}
}
return;
}
case hasChangesets: {
yield runVersion({
script: getOptionalInput("version"),
gitlabToken: GITLAB_TOKEN,
mrTitle: getOptionalInput("title"),
mrTargetBranch: getOptionalInput("target_branch"),
commitMessage: getOptionalInput("commit"),
removeSourceBranch: core.getInput("remove_source_branch") === "true",
hasPublishScript
});
if (onlyChangesets) {
execSync(onlyChangesets);
}
}
}
});
exports.comment = comment;
exports.createApi = createApi;
exports.createRelease = createRelease;
exports.env = env;
exports.main = main;
exports.projectId = projectId;
exports.ref = ref;
exports.runPublish = runPublish;
exports.runVersion = runVersion;