@cdwr/nx-migrate-action
Version:
The Nx Migrate GitHub Action will keep your workspace up to date.
1,028 lines (984 loc) • 34.5 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// packages/nx-migrate-action/src/lib/main.ts
var core21 = __toESM(require("@actions/core"), 1);
// packages/nx-migrate-action/src/lib/nx-migrate.ts
var core20 = __toESM(require("@actions/core"), 1);
// packages/core/src/lib/actions/add-pull-request-comment.ts
var github = __toESM(require("@actions/github"), 1);
// packages/core/src/lib/actions/with-github.ts
var import_request_error = require("@octokit/request-error");
var import_http_status_codes = require("http-status-codes");
async function withGitHub(operation, option) {
try {
return await operation();
} catch (error2) {
if (error2 instanceof import_request_error.RequestError) {
switch (error2.status) {
case import_http_status_codes.StatusCodes.UNAUTHORIZED:
throw new Error(
`Authentication failed. Please check your GitHub token.
${error2.message}`
);
case import_http_status_codes.StatusCodes.FORBIDDEN:
throw new Error(
`Permission to the operation was denied. Please check your GitHub token.
${error2.message}`
);
case import_http_status_codes.StatusCodes.NOT_FOUND:
if (option === "not-found-returns-null") {
return null;
}
throw new Error(
`Requested information was not found.
${error2.message}`
);
default:
throw new Error(
`Request failed with ${error2.status} - ${(0, import_http_status_codes.getReasonPhrase)(error2.status)}.
${error2.message}`
);
}
}
throw error2;
}
}
// packages/core/src/lib/actions/add-pull-request-comment.ts
var addPullRequestComment = async (token, pullRequest, comment) => {
const octokit = github.getOctokit(token);
const {
data: { id }
} = await withGitHub(
() => octokit.rest.issues.createComment({
...github.context.repo,
issue_number: pullRequest,
body: comment
})
);
return id;
};
// packages/core/src/lib/actions/get-repository-default-branch.ts
var github2 = __toESM(require("@actions/github"), 1);
var getRepositoryDefaultBranch = async (token) => {
const octokit = github2.getOctokit(token);
const {
data: { default_branch }
} = await withGitHub(
async () => octokit.rest.repos.get({
...github2.context.repo
})
);
return default_branch;
};
// packages/core/src/lib/actions/get-deploy-env.ts
var import_zod = require("zod");
var EnvironmentSchema = import_zod.z.enum(["preview", "production"]);
// packages/core/src/lib/actions/get-pull-request.ts
var core = __toESM(require("@actions/core"), 1);
var github3 = __toESM(require("@actions/github"), 1);
var getPullRequest = async (token, pullRequest) => {
const octokit = github3.getOctokit(token);
core.debug(`Get pull request from number #${pullRequest}`);
const pr = await withGitHub(
() => octokit.rest.pulls.get({
...github3.context.repo,
pull_number: pullRequest
}),
"not-found-returns-null"
);
if (!pr) {
core.debug(`Pull request #${pullRequest} could not be found`);
return void 0;
}
return pr.data;
};
// packages/core/src/lib/actions/print-github-context.ts
var core2 = __toESM(require("@actions/core"), 1);
var github4 = __toESM(require("@actions/github"), 1);
var printGitHubContext = () => {
core2.info("== Repo ==");
core2.info(`- owner: ${github4.context.repo.owner}`);
core2.info(`- repo: ${github4.context.repo.repo}`);
core2.info("== Misc ==");
for (const [key, value] of Object.entries(github4.context)) {
if (typeof value === "string") {
core2.info(`- ${key}: ${value}`);
}
}
};
// packages/nx-migrate-action/src/lib/utils/add-pull-request-assignees.ts
var core3 = __toESM(require("@actions/core"), 1);
var github5 = __toESM(require("@actions/github"), 1);
var addPullRequestAssignees = async (config, pullRequest) => {
const { prAssignees, token } = config;
if (!prAssignees.length) {
return;
}
const assignees = Array.isArray(prAssignees) ? prAssignees : [prAssignees];
const octokit = github5.getOctokit(token);
await withGitHub(
() => octokit.rest.issues.addAssignees({
...github5.context.repo,
issue_number: pullRequest,
assignees
})
);
core3.info(
`Added assignees '${assignees.join(",")}' to pull request #${pullRequest}`
);
};
// packages/nx-migrate-action/src/lib/utils/add-pull-request-label.ts
var core4 = __toESM(require("@actions/core"), 1);
var github6 = __toESM(require("@actions/github"), 1);
// packages/nx-migrate-action/src/lib/utils/definitions.ts
var PULL_REQUEST_LABEL = "nx migrate";
// packages/nx-migrate-action/src/lib/utils/add-pull-request-label.ts
var addPullRequestLabel = async (config, pullRequest) => {
const { token } = config;
const labels = [PULL_REQUEST_LABEL];
const octokit = github6.getOctokit(token);
await withGitHub(
() => octokit.rest.issues.addLabels({
...github6.context.repo,
issue_number: pullRequest,
labels
})
);
core4.info(
`Added labels '${labels.join(",")}' to pull request #${pullRequest}`
);
};
// packages/nx-migrate-action/src/lib/utils/cleanup-pull-requests.ts
var core5 = __toESM(require("@actions/core"), 1);
var github7 = __toESM(require("@actions/github"), 1);
var cleanupPullRequests = async (config, pullRequest) => {
core5.info("Cleaning up deprecated open pull requests");
const { token } = config;
const octokit = github7.getOctokit(token);
const { data: openPullRequests } = await withGitHub(
() => octokit.rest.pulls.list({
...github7.context.repo,
state: "open"
})
);
if (!openPullRequests.length) {
core5.info("No open pull requests found");
return;
}
for (const openPR of openPullRequests) {
if (openPR.labels.find((label) => label.name === PULL_REQUEST_LABEL) && openPR.number !== pullRequest) {
await withGitHub(
() => octokit.rest.pulls.update({
...github7.context.repo,
pull_number: openPR.number,
state: "closed"
})
);
core5.info(`Closed deprecated pull request #${openPR.number}`);
await withGitHub(
() => octokit.rest.issues.createComment({
...github7.context.repo,
issue_number: openPR.number,
body: `Auto-closed - replaced by new pull request #${pullRequest}`
})
);
core5.info(`Added comment to deprecated pull request #${openPR.number}`);
await withGitHub(
() => octokit.rest.git.deleteRef({
...github7.context.repo,
ref: `heads/${openPR.head.ref}`
})
);
core5.info(
`Deleted branch ${openPR.head.ref} of pull request #${openPR.number}`
);
}
}
};
// packages/nx-migrate-action/src/lib/utils/create-and-push-commit.ts
var exec = __toESM(require("@actions/exec"), 1);
// packages/nx-migrate-action/src/lib/utils/get-feature-branch-name.ts
var getFeatureBranchName = (version) => `update-nx-workspace-${version}`;
// packages/nx-migrate-action/src/lib/utils/create-and-push-commit.ts
var createAndPushCommit = async (config, latestVersion) => {
const { author } = config;
const commitMessage = `build(repo): update nx workspace to ${latestVersion}`;
const authorOption = author ? `--author="${author.name} <${author.email}>"` : "";
const commitOptions = [
authorOption,
"-m",
commitMessage,
"--no-verify"
].filter(Boolean);
const { stdout: fileChanges } = await exec.getExecOutput(
"git",
["status", "--porcelain"],
{
silent: true
}
);
if (fileChanges.trim() === "") {
throw new Error("Expected to find file changes to commit");
}
await exec.exec("git", ["add", "."]);
await exec.exec("git", ["commit", ...commitOptions]);
await exec.exec("git", [
"push",
"-u",
"origin",
getFeatureBranchName(latestVersion)
]);
};
// packages/nx-migrate-action/src/lib/utils/create-local-branch.ts
var core6 = __toESM(require("@actions/core"), 1);
var exec3 = __toESM(require("@actions/exec"), 1);
var createLocalBranch = async (config, latestVersion) => {
const { mainBranch } = config;
const featureBranch = getFeatureBranchName(latestVersion);
await exec3.exec("git", [
"checkout",
"--no-track",
"-B",
featureBranch,
`origin/${mainBranch}`
]);
core6.info(`Created local branch '${featureBranch}'`);
};
// packages/nx-migrate-action/src/lib/utils/create-pull-request.ts
var core7 = __toESM(require("@actions/core"), 1);
var github8 = __toESM(require("@actions/github"), 1);
var createPullRequest = async (config, versionInfo, status) => {
const { mainBranch, skipE2E, skipTests, token } = config;
const octokit = github8.getOctokit(token);
const { currentVersion, latestVersion } = versionInfo;
const { e2ePass, testsPass } = status;
const branchName = getFeatureBranchName(latestVersion);
const prTitle = `Update @nx/workspace to ${latestVersion}`;
const prBody = [`Update Nx from ${currentVersion} to ${latestVersion}`, ""];
if (!skipTests) {
prBody.push(testsPass ? "\u2705 Tests passed" : "\u26A0\uFE0F Tests failed", "");
}
if (!skipE2E) {
prBody.push(e2ePass ? "\u2705 E2E tests passed" : "\u26A0\uFE0F E2E tests failed", "");
}
prBody.push(
"",
"> Auto-generated by [@cdwr/nx-migrate-action][1]",
"",
"[1]: https://github.com/codeware-sthlm/codeware/packages/nx-migrate-action"
);
const {
data: { number }
} = await withGitHub(
() => octokit.rest.pulls.create({
...github8.context.repo,
title: prTitle,
body: prBody.join("\n"),
head: branchName,
base: mainBranch,
draft: false
})
);
core7.info(`Created pull request #${number}`);
return number;
};
// packages/nx-migrate-action/src/lib/utils/discard-unstaged-changes.ts
var core8 = __toESM(require("@actions/core"), 1);
var exec5 = __toESM(require("@actions/exec"), 1);
var discardUnstagedChanges = async () => {
await exec5.exec("git", ["checkout", "--", "."]);
core8.info("All unstaged changes were discarded");
};
// packages/nx-migrate-action/src/lib/utils/enable-pull-request-auto-merge.ts
var core9 = __toESM(require("@actions/core"), 1);
var github9 = __toESM(require("@actions/github"), 1);
var enablePullRequestAutoMerge = async (token, pullRequest, mergeMethod = "REBASE") => {
const octokit = github9.getOctokit(token);
const pullRequestData = await getPullRequest(token, pullRequest);
if (!pullRequestData) {
core9.error(
`Pull request #${pullRequest} could not be found, aborting auto-merge`
);
return;
}
await octokit.graphql(
/* GraphQL */
`
mutation EnablePullRequestAutoMerge(
$pullRequestId: ID!
$mergeMethod: PullRequestMergeMethod!
) {
enablePullRequestAutoMerge(
input: { pullRequestId: $pullRequestId, mergeMethod: $mergeMethod }
) {
pullRequest {
autoMergeRequest {
enabledAt
}
}
}
}
`,
{
pullRequestId: pullRequestData.node_id,
mergeMethod
}
);
core9.info(
`Auto-merge is enabled for pull request #${pullRequest} with '${mergeMethod}'`
);
};
// packages/nx-migrate-action/src/lib/utils/exists-feature-branch-on-remote.ts
var core10 = __toESM(require("@actions/core"), 1);
var exec7 = __toESM(require("@actions/exec"), 1);
var existsFeatureBranchOnRemote = async (latestVersion) => {
const branchName = getFeatureBranchName(latestVersion);
const { stdout: prBranch } = await exec7.getExecOutput("git", [
"ls-remote",
"--heads",
"origin",
branchName
]);
if (prBranch.trim() !== "") {
core10.info(`Feature branch '${branchName}' exists on remote`);
return true;
}
return false;
};
// packages/nx-migrate-action/src/lib/utils/fetch-remote-changes.ts
var exec8 = __toESM(require("@actions/exec"), 1);
var fetchRemoteChanges = async () => await exec8.exec("git", ["fetch", "origin"]);
// packages/nx-migrate-action/src/lib/utils/get-migrate-config.ts
var core12 = __toESM(require("@actions/core"), 1);
var github11 = __toESM(require("@actions/github"), 1);
// packages/nx-migrate-action/src/lib/utils/get-actor-id.ts
var core11 = __toESM(require("@actions/core"), 1);
var github10 = __toESM(require("@actions/github"), 1);
var getActorId = async (token) => {
const octokit = github10.getOctokit(token);
const username = github10.context.actor;
core11.debug(`Get user from actor '${username}'`);
const actor = await withGitHub(
async () => await octokit.rest.users.getByUsername({
username
}),
"not-found-returns-null"
);
if (!actor) {
core11.debug(`User '${username}' could not be found`);
return void 0;
}
return actor.data.id;
};
// packages/nx-migrate-action/src/lib/utils/parse-name-email.ts
var parseNameEmail = (text) => {
if (!text) {
return {
name: "",
email: ""
};
}
let name = "";
let email = "";
const nameEmailPattern = /^([^;<\s][^<]{0,254})(?:\s{0,10})<([^>]{1,256})>$/;
const match = text.match(nameEmailPattern);
if (match) {
name = match[1].trim();
email = match[2].trim();
}
if (!name || !email) {
throw new Error(
`'${text}' is not following the pattern 'Name <user@domain.io>'`
);
}
return {
name,
email
};
};
// packages/nx-migrate-action/src/lib/utils/schema.ts
var import_zod2 = require("zod");
var EmailValidation = {
standardEmail: import_zod2.z.string().email(),
githubBotEmail: import_zod2.z.string().regex(
/^\d+\+[\w-]+\[bot\]@users\.noreply\.github\.com$/,
"Invalid GitHub bot email"
),
anyBotEmail: import_zod2.z.string().refine(
(email) => {
const githubBotPattern = /^\d+\+[\w-]+\[bot\]@users\.noreply\.github\.com$/;
const regularEmailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return githubBotPattern.test(email) || regularEmailPattern.test(email);
},
{
message: "Invalid email address"
}
)
};
var ActionInputsSchema = import_zod2.z.object({
author: import_zod2.z.string(),
autoMerge: import_zod2.z.boolean(),
checkToken: import_zod2.z.boolean(),
committer: import_zod2.z.string(),
dryRun: import_zod2.z.boolean(),
mainBranch: import_zod2.z.string(),
packagePatterns: import_zod2.z.array(import_zod2.z.string()),
prAssignees: import_zod2.z.string(),
skipTests: import_zod2.z.boolean(),
skipE2E: import_zod2.z.boolean(),
token: import_zod2.z.string().min(1, "token is required")
});
var MigrateConfigSchema = ActionInputsSchema.merge(
import_zod2.z.object({
author: import_zod2.z.object({
name: import_zod2.z.string(),
email: EmailValidation.anyBotEmail
}).optional(),
committer: import_zod2.z.object({
name: import_zod2.z.string().min(1, "committer name is required"),
email: EmailValidation.anyBotEmail
}),
mainBranch: import_zod2.z.string().min(1, "main branch is required"),
packagePatterns: import_zod2.z.array(import_zod2.z.string().min(1)).min(1, "at least one package pattern is required"),
prAssignees: import_zod2.z.array(import_zod2.z.string().min(1))
})
);
// packages/nx-migrate-action/src/lib/utils/get-migrate-config.ts
var getMigrateConfig = async (inputs) => {
const {
author: authorInput,
autoMerge: autoMergeInput,
checkToken,
committer: committerInput,
dryRun,
mainBranch: mainBranchInput,
packagePatterns,
prAssignees: prAssigneesInput,
skipTests,
skipE2E,
token
} = inputs;
const octokit = github11.getOctokit(token);
const mainBranch = mainBranchInput || await getRepositoryDefaultBranch(token);
const {
data: { allow_auto_merge }
} = await withGitHub(
() => octokit.rest.repos.get({
...github11.context.repo
})
);
if (!allow_auto_merge && autoMergeInput) {
core12.warning(
"Auto-merge is not enabled for this repository, ignoring auto-merge option"
);
}
const autoMerge = !!allow_auto_merge && autoMergeInput;
let author = parseNameEmail(authorInput);
if (!author.email) {
const id = await getActorId(token);
if (id) {
author = {
name: github11.context.actor,
email: `${id}+${github11.context.actor}@users.noreply.github.com`
};
}
}
let committer = parseNameEmail(committerInput);
if (!committer.email) {
committer = {
name: "github-actions[bot]",
email: "41898282+github-actions[bot]@users.noreply.github.com"
};
}
if (!packagePatterns.length) {
packagePatterns.push("packages/**/package.json");
}
const prAssignees = prAssigneesInput.split(",").filter(Boolean);
const config = {
author: author.email ? author : void 0,
autoMerge,
checkToken,
committer,
dryRun,
mainBranch,
packagePatterns,
prAssignees,
skipTests,
skipE2E,
token
};
core12.info(JSON.stringify(config, null, 2));
return MigrateConfigSchema.parse(config);
};
// packages/nx-migrate-action/src/lib/utils/get-nx-version-info.ts
var core13 = __toESM(require("@actions/core"), 1);
var exec10 = __toESM(require("@actions/exec"), 1);
async function getNxVersionInfo() {
core13.info("Resolve nx versions");
const output = await exec10.getExecOutput(
"npm",
["list", "@nx/workspace", "--depth=0", "--json"],
{ silent: true }
);
const currentVersion = JSON.parse(output.stdout).dependencies["@nx/workspace"].version;
core13.info(`Current version: ${currentVersion}`);
const currentMajor = parseInt(currentVersion.split(".")[0]);
core13.info(`Current major: ${currentMajor}`);
const latestOutput = await exec10.getExecOutput(
"npm",
["view", "@nx/workspace", "version"],
{ silent: true }
);
const latestVersion = latestOutput.stdout.trim();
core13.info(`Latest version: ${latestVersion}`);
const latestMajor = parseInt(latestVersion.split(".")[0]);
core13.info(`Latest major: ${latestMajor}`);
const isMajorUpdate = latestMajor > currentMajor;
core13.info(`Major update: ${isMajorUpdate}`);
const isOutdated = currentVersion !== latestVersion;
core13.info(`Outdated: ${isOutdated}`);
return {
currentVersion,
latestVersion,
isMajorUpdate,
isOutdated
};
}
// packages/nx-migrate-action/src/lib/utils/get-token-permissions.ts
var core14 = __toESM(require("@actions/core"), 1);
var github12 = __toESM(require("@actions/github"), 1);
var getTokenPermissions = async (token) => {
const octokit = github12.getOctokit(token);
core14.debug("Get token permissions");
const {
data: { login: username },
headers
} = await withGitHub(async () => await octokit.rest.users.getAuthenticated());
const expirationHeader = headers["github-authentication-token-expiration"];
const expiration = expirationHeader ? new Date(expirationHeader) : null;
const isValid = expiration ? expiration > /* @__PURE__ */ new Date() : true;
const { data: repos } = await octokit.rest.repos.listForAuthenticatedUser();
const permissions = repos.find(
(repo) => repo.name === github12.context.repo.repo
)?.permissions;
if (!permissions) {
throw new Error("Repository permissions not found");
}
const scopesHeader = headers["x-oauth-scopes"];
const scopes = scopesHeader ? scopesHeader.split(",").map((scope) => scope.trim()).filter(Boolean) : void 0;
return {
type: "x-oauth-scopes" in headers ? "classic" : "fine-grained",
isValid,
username,
expiration,
scopes,
repoPermissions: permissions,
resolvedPermissions: {
pullRequest: scopes?.includes("repo") ?? permissions.pull_requests === "write",
repo: scopes?.includes("repo") ?? permissions.contents === "write",
workflow: scopes?.includes("workflow") ?? permissions.workflows === "write"
}
};
};
// packages/nx-migrate-action/src/lib/utils/lookup-pull-request.ts
var github13 = __toESM(require("@actions/github"), 1);
var lookupPullRequest = async (config, latestVersion) => {
const { token } = config;
const branchName = getFeatureBranchName(latestVersion);
const octokit = github13.getOctokit(token);
const { data: pullRequests } = await withGitHub(
() => octokit.rest.pulls.list({
...github13.context.repo,
state: "open",
head: `${github13.context.repo.owner}:${branchName}`
})
);
if (pullRequests.length > 1) {
throw new Error(`Multiple pull requests found for branch ${branchName}`);
}
return pullRequests.length === 1 ? pullRequests[0].number : void 0;
};
// packages/nx-migrate-action/src/lib/utils/print-commit-signature-details.ts
var core15 = __toESM(require("@actions/core"), 1);
var github14 = __toESM(require("@actions/github"), 1);
// packages/nx-migrate-action/src/lib/utils/get-current-commit-sha.ts
var exec11 = __toESM(require("@actions/exec"), 1);
var getCurrentCommitSha = async () => {
let sha = "";
const options = {
listeners: {
stdout: (data) => {
sha += data.toString();
}
}
};
await exec11.exec("git", ["rev-parse", "HEAD"], options);
return sha.trim();
};
// packages/nx-migrate-action/src/lib/utils/print-commit-signature-details.ts
var printCommitSignatureDetails = async (config) => {
const { token } = config;
const octokit = github14.getOctokit(token);
const ref = await getCurrentCommitSha();
const {
data: { commit, committer, sha }
} = await withGitHub(
() => octokit.rest.repos.getCommit({
...github14.context.repo,
ref
})
);
core15.info(`Verification status for commit ${sha}`);
core15.info(`- Verified: ${commit.verification?.verified}`);
core15.info(`- Reason: ${commit.verification?.reason}`);
core15.info(`- Committer: ${committer?.name}`);
};
// packages/nx-migrate-action/src/lib/utils/print-token-permissions.ts
var core16 = __toESM(require("@actions/core"), 1);
var printTokenPermissions = (token) => {
core16.info("== Token ==");
core16.info(`- type: ${token.type}`);
core16.info(`- isValid: ${token.isValid}`);
core16.info(`- username: ${token.username}`);
core16.info(`- expiration: ${token.expiration}`);
core16.info(`- scopes: ${token.scopes?.join(", ")}`);
core16.info("== Repo permissions ==");
for (const [key, value] of Object.entries(token.repoPermissions)) {
core16.info(`- ${key}: ${value}`);
}
core16.info("== Resolved permissions ==");
for (const [key, value] of Object.entries(token.resolvedPermissions)) {
core16.info(`- ${key}: ${value}`);
}
};
// packages/nx-migrate-action/src/lib/utils/run-migration.ts
var core17 = __toESM(require("@actions/core"), 1);
var exec13 = __toESM(require("@actions/exec"), 1);
var import_devkit = require("@nx/devkit");
var import_replace_in_file = require("replace-in-file");
var runMigration = async (config, latestVersion) => {
const pmc = (0, import_devkit.getPackageManagerCommand)();
core17.info("Running Nx migrate");
await exec13.exec(pmc.exec, ["nx", "migrate", latestVersion]);
core17.info("Adding create-nx-workspace dependency");
await exec13.exec(pmc.exec, [
"nx",
"add",
`create-nx-workspace@${latestVersion}`
]);
core17.info("Installing dependencies");
await exec13.exec(pmc.install);
const migrationsExist = await exec13.exec("test", ["-f", "migrations.json"], {
ignoreReturnCode: true
}) === 0;
if (migrationsExist) {
core17.info("Running migrations");
await exec13.exec(pmc.exec, ["nx", "migrate", "--run-migrations"]);
} else {
core17.info("No migrations found");
}
core17.info("Update version references in package.json files");
core17.debug("Find and update semantic versions");
await (0, import_replace_in_file.replaceInFile)({
files: config.packagePatterns,
from: /"(?:create-nx-workspace|nx|@nx\/[^"]*)": "\d+\.\d+\.\d+"/g,
to: (match) => {
const packageName = match.split(":")[0];
const newValue = `${packageName}: "${latestVersion}"`;
core17.debug(`Found semver version '${match}' -> '${newValue}'`);
return newValue;
},
allowEmptyPaths: true
});
core17.debug("Find and update major versions");
await (0, import_replace_in_file.replaceInFile)({
files: config.packagePatterns,
from: /"(?:create-nx-workspace|nx|@nx\/[^"]*)": "(\d+)\.x"/g,
to: (match) => {
const packageName = match.split(":")[0];
const major = latestVersion.split(".")[0];
const newValue = `${packageName}: "${major}.x"`;
core17.debug(`Found dynamic version '${match}' -> '${newValue}'`);
return newValue;
},
allowEmptyPaths: true
});
core17.info("Migration completed");
};
// packages/nx-migrate-action/src/lib/utils/run-nx-e2e.ts
var exec15 = __toESM(require("@actions/exec"), 1);
var import_devkit2 = require("@nx/devkit");
async function runNxE2e() {
const pmc = (0, import_devkit2.getPackageManagerCommand)();
try {
await exec15.exec(pmc.exec, ["nx", "run-many", "-t", "e2e", "-c", "ci"]);
return true;
} catch (error2) {
return false;
}
}
// packages/nx-migrate-action/src/lib/utils/run-nx-tests.ts
var exec17 = __toESM(require("@actions/exec"), 1);
var import_devkit3 = require("@nx/devkit");
async function runNxTests() {
const pmc = (0, import_devkit3.getPackageManagerCommand)();
try {
await exec17.exec(pmc.exec, [
"nx",
"run-many",
"-t",
"lint,test,build",
"-c",
"ci"
]);
return true;
} catch (error2) {
return false;
}
}
// packages/nx-migrate-action/src/lib/utils/set-git-credentials.ts
var core18 = __toESM(require("@actions/core"), 1);
var exec19 = __toESM(require("@actions/exec"), 1);
var github15 = __toESM(require("@actions/github"), 1);
var setGitCredentials = async (config) => {
const { committer, token } = config;
const { repo, owner } = github15.context.repo;
await exec19.exec("git", ["config", "user.name", committer.name]);
await exec19.exec("git", ["config", "user.email", committer.email]);
core18.info(`Git committer name set to '${committer.name}'`);
core18.info(`Git committer email set to '${committer.email}'`);
const remoteUrl = `https://x-access-token:${token}@github.com/${owner}/${repo}.git`;
await exec19.exec("git", ["remote", "set-url", "origin", remoteUrl]);
core18.info(`Git remote URL set to '${remoteUrl}'`);
};
// packages/nx-migrate-action/src/lib/utils/stage-all-changes.ts
var core19 = __toESM(require("@actions/core"), 1);
var exec21 = __toESM(require("@actions/exec"), 1);
var stageAllChanges = async () => {
await exec21.exec("git", ["add", "."]);
core19.info("All changes was staged");
};
// packages/nx-migrate-action/src/lib/nx-migrate.ts
async function nxMigrate(inputs, throwOnError = false) {
try {
core20.info("Starting nx migration process");
core20.startGroup("GitHub context details");
printGitHubContext();
core20.endGroup();
core20.startGroup("Get migration configuration");
const config = await getMigrateConfig(inputs);
core20.endGroup();
core20.startGroup("Set git credentials");
await setGitCredentials(config);
core20.endGroup();
core20.startGroup("Check token is valid and has proper permissions");
if (config.checkToken) {
try {
const response = await getTokenPermissions(config.token);
const { isValid, resolvedPermissions } = response;
printTokenPermissions(response);
if (!isValid) {
throw new Error("Token is invalid or expired");
}
if (Object.values(resolvedPermissions).some((value) => value === false)) {
throw new Error("Token is missing some required permissions");
}
} catch (error2) {
if (error2 instanceof Error) {
core20.warning(`Token check failed: ${error2.message}`);
} else {
core20.warning("Token check failed");
core20.warning(error2);
}
core20.warning(
"Could not determine token permissions, continue migration anyway"
);
}
} else {
core20.info("Disabled by configuration");
}
core20.endGroup();
core20.startGroup("Analyze current migration state");
const { currentVersion, isMajorUpdate, isOutdated, latestVersion } = await getNxVersionInfo();
if (!isOutdated) {
core20.info("Nx workspace is up to date, skipping migration");
return {
currentVersion,
latestVersion,
isMajorUpdate,
isMigrated: false,
pullRequest: void 0
};
}
if (await existsFeatureBranchOnRemote(latestVersion)) {
const existingPullRequest = await lookupPullRequest(
config,
latestVersion
);
if (!existingPullRequest) {
throw new Error(
`Expected to find a pull request for branch '${latestVersion}'`
);
}
core20.info(
`Active pull request #${existingPullRequest} exists, skipping migration`
);
return {
currentVersion,
isMajorUpdate,
isMigrated: false,
latestVersion,
pullRequest: existingPullRequest
};
}
core20.endGroup();
if (!config.dryRun) {
core20.startGroup("Fetch remote changes");
await fetchRemoteChanges();
core20.endGroup();
core20.startGroup("Create local branch");
await createLocalBranch(config, latestVersion);
core20.endGroup();
core20.startGroup("Run migration");
await runMigration(config, latestVersion);
await stageAllChanges();
core20.endGroup();
let testsPass;
if (!config.skipTests) {
core20.startGroup("Run tests on migration changes");
testsPass = await runNxTests();
core20.endGroup();
}
let e2ePass;
if ((config.skipTests || testsPass) && !config.skipE2E) {
core20.startGroup("Run e2e on migration changes");
e2ePass = await runNxE2e();
core20.endGroup();
}
core20.startGroup("Cleanup changes affected by tests");
await discardUnstagedChanges();
core20.endGroup();
core20.startGroup("Create commit on remote");
await createAndPushCommit(config, latestVersion);
await printCommitSignatureDetails(config);
core20.endGroup();
core20.startGroup("Create pull request");
const pullRequest = await createPullRequest(
config,
{ currentVersion, latestVersion },
{
e2ePass,
testsPass
}
);
if (config.prAssignees.length > 0) {
await addPullRequestAssignees(config, pullRequest);
}
await addPullRequestLabel(config, pullRequest);
if (config.autoMerge) {
if (isMajorUpdate) {
core20.info("Skip auto-merge for major version migrations");
await addPullRequestComment(
config.token,
pullRequest,
"Auto-merge is disabled for major version migrations"
);
} else if (testsPass === false || e2ePass === false) {
core20.info("Skip auto-merge since some tests failed");
await addPullRequestComment(
config.token,
pullRequest,
"Auto-merge was disabled since some tests failed"
);
} else {
await enablePullRequestAutoMerge(config.token, pullRequest, "REBASE");
}
}
await cleanupPullRequests(config, pullRequest);
core20.endGroup();
return {
currentVersion,
isMajorUpdate,
isMigrated: true,
latestVersion,
pullRequest
};
} else {
core20.info("Skip nx migration [dry-run]");
return {
currentVersion,
isMajorUpdate,
isMigrated: false,
latestVersion,
pullRequest: void 0
};
}
} catch (error2) {
if (error2 instanceof Error) {
core20.setFailed(error2.message);
if (throwOnError) {
throw error2.message;
}
}
return {};
}
}
// packages/nx-migrate-action/src/lib/main.ts
async function run() {
try {
const inputs = ActionInputsSchema.parse({
token: core21.getInput("token", { required: true }),
autoMerge: core21.getBooleanInput("auto-merge"),
checkToken: core21.getBooleanInput("check-token"),
committer: core21.getInput("committer"),
author: core21.getInput("author"),
mainBranch: core21.getInput("main-branch"),
packagePatterns: core21.getMultilineInput("package-patterns"),
prAssignees: core21.getInput("pull-request-assignees"),
skipTests: core21.getBooleanInput("skip-tests"),
skipE2E: core21.getBooleanInput("skip-e2e"),
dryRun: core21.getBooleanInput("dry-run")
});
core21.debug(`Inputs:
${JSON.stringify(inputs, null, 2)}`);
const {
currentVersion,
isMajorUpdate,
isMigrated,
latestVersion,
pullRequest
} = await nxMigrate(inputs);
core21.setOutput("current-version", currentVersion);
core21.setOutput("latest-version", latestVersion);
core21.setOutput("is-major-update", isMajorUpdate);
core21.setOutput("is-migrated", isMigrated);
core21.setOutput("pull-request", pullRequest);
} catch (error2) {
if (error2 instanceof Error) {
core21.setFailed(error2.message);
}
}
}
// packages/nx-migrate-action/src/action.ts
run();