semantic-release/test/integration.test.js

740 lines
28 KiB
JavaScript

import path from "path";
import test from "ava";
import * as td from "testdouble";
import { escapeRegExp } from "lodash-es";
import fsExtra from "fs-extra";
import { execa } from "execa";
import { WritableStreamBuffer } from "stream-buffers";
import delay from "delay";
import getAuthUrl from "../lib/get-git-auth-url.js";
import { SECRET_REPLACEMENT } from "../lib/definitions/constants.js";
import {
gitCheckout,
gitCommits,
gitGetNote,
gitHead,
gitPush,
gitRemoteTagHead,
gitRepo,
gitTagHead,
merge,
} from "./helpers/git-utils.js";
import { npmView } from "./helpers/npm-utils.js";
import * as gitbox from "./helpers/gitbox.js";
import * as mockServer from "./helpers/mockserver.js";
import * as npmRegistry from "./helpers/npm-registry.js";
const { readJson, writeJson } = fsExtra;
/* eslint camelcase: ["error", {properties: "never"}] */
// Environment variables used with semantic-release cli (similar to what a user would setup)
const { GITHUB_ACTION, GITHUB_ACTIONS, GITHUB_TOKEN, ...processEnvWithoutGitHubActionsVariables } = process.env;
let env;
// Environment variables used only for the local npm command used to do verification
const npmTestEnv = {
...process.env,
...npmRegistry.authEnv(),
npm_config_registry: npmRegistry.url,
};
const cli = path.resolve("./bin/semantic-release.js");
const pluginError = path.resolve("./test/fixtures/plugin-error");
const pluginInheritedError = path.resolve("./test/fixtures/plugin-error-inherited");
const pluginLogEnv = path.resolve("./test/fixtures/plugin-log-env");
const pluginEsmNamedExports = path.resolve("./test/fixtures/plugin-esm-named-exports");
test.before(async () => {
await Promise.all([gitbox.start(), npmRegistry.start(), mockServer.start()]);
env = {
...processEnvWithoutGitHubActionsVariables,
...npmRegistry.authEnv(),
CI: "true",
GH_TOKEN: gitbox.gitCredential,
TRAVIS: "true",
TRAVIS_BRANCH: "master",
TRAVIS_PULL_REQUEST: "false",
GITHUB_API_URL: mockServer.url,
};
});
test.after.always(async () => {
await Promise.all([gitbox.stop(), npmRegistry.stop(), mockServer.stop()]);
});
test("Release patch, minor and major versions", async (t) => {
const packageName = "test-release";
const owner = "git";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
publishConfig: { registry: npmRegistry.url },
release: { branches: ["master", "next"], success: false, fail: false },
});
// Create a npm-shrinkwrap.json file
await execa("npm", ["shrinkwrap"], { env: npmTestEnv, cwd, extendEnv: false });
/* No release */
let verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
t.log("Commit a chore");
await gitCommits(["chore: Init repository"], { cwd });
t.log("$ semantic-release");
let { stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false });
t.regex(stdout, /There are no relevant changes, so no new version is released/);
t.is(exitCode, 0);
/* Initial release */
let version = "1.0.0";
verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
let createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release");
({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }));
t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and npm-shrinkwrap.json have been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
let {
"dist-tags": { latest: releasedVersion },
} = await npmView(packageName, npmTestEnv);
let head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
/* Patch release */
version = "1.0.1";
verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a fix");
await gitCommits(["fix: bar"], { cwd });
t.log("$ semantic-release");
({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }));
t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and npm-shrinkwrap.json have been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
({
"dist-tags": { latest: releasedVersion },
} = await npmView(packageName, npmTestEnv));
head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
/* Minor release */
version = "1.1.0";
verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a feature");
await gitCommits(["feat: baz"], { cwd });
t.log("$ semantic-release");
({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }));
t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and npm-shrinkwrap.json have been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
({
"dist-tags": { latest: releasedVersion },
} = await npmView(packageName, npmTestEnv));
head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion}`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
/* Major release on next */
version = "2.0.0";
verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a breaking change on next");
await gitCheckout("next", true, { cwd });
await gitPush("origin", "next", { cwd });
await gitCommits(["feat: foo\n\n BREAKING CHANGE: bar"], { cwd });
t.log("$ semantic-release");
({ stdout, exitCode } = await execa(cli, [], { env: { ...env, TRAVIS_BRANCH: "next" }, cwd, extendEnv: false }));
t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and npm-shrinkwrap.json have been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
t.is((await readJson(path.resolve(cwd, "npm-shrinkwrap.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
({
"dist-tags": { next: releasedVersion },
} = await npmView(packageName, npmTestEnv));
head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next"]}');
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion} on @next`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
/* Merge next into master */
version = "2.0.0";
const releaseId = 1;
verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
const getReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases/tags/v2.0.0`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { id: releaseId }, method: "GET" }
);
const updateReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases/${releaseId}`,
{
body: { name: `v${version}`, prerelease: false },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` }, method: "PATCH" }
);
t.log("Merge next into master");
await gitCheckout("master", false, { cwd });
await merge("next", { cwd });
await gitPush("origin", "master", { cwd });
t.log("$ semantic-release");
({ stdout, exitCode } = await execa(cli, [], { env, cwd, extendEnv: false }));
t.regex(stdout, new RegExp(`Updated GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Adding version ${version} to npm registry on dist-tag latest`));
t.is(exitCode, 0);
// Wait for 3s as the change of dist-tag takes time to be reflected in the registry
await delay(3000);
// Retrieve the published package from the registry and check version and gitHead
({
"dist-tags": { latest: releasedVersion },
} = await npmView(packageName, npmTestEnv));
t.is(releasedVersion, version);
t.is(await gitGetNote(`v${version}`, { cwd }), '{"channels":["next",null]}');
t.is(await gitTagHead(`v${version}`, { cwd }), await gitTagHead(`v${version}`, { cwd }));
t.is(
await gitRemoteTagHead(authUrl, `v${version}`, { cwd }),
await gitRemoteTagHead(authUrl, `v${version}`, { cwd })
);
t.log(`+ added ${releasedVersion}`);
await mockServer.verify(verifyMock);
await mockServer.verify(getReleaseMock);
await mockServer.verify(updateReleaseMock);
});
test("Exit with 1 if a plugin is not found", async (t) => {
const packageName = "test-plugin-not-found";
const owner = "test-repo";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd } = await gitRepo();
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: `git+https://github.com/${owner}/${packageName}` },
release: { analyzeCommits: "non-existing-path", success: false, fail: false },
});
const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false }));
t.is(exitCode, 1);
t.regex(stderr, /Cannot find module/);
});
test("Exit with 1 if a shareable config is not found", async (t) => {
const packageName = "test-config-not-found";
const owner = "test-repo";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd } = await gitRepo();
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: `git+https://github.com/${owner}/${packageName}` },
release: { extends: "non-existing-path", success: false, fail: false },
});
const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false }));
t.is(exitCode, 1);
t.regex(stderr, /Cannot find module/);
});
test("Exit with 1 if a shareable config reference a not found plugin", async (t) => {
const packageName = "test-config-ref-not-found";
const owner = "test-repo";
const shareable = { analyzeCommits: "non-existing-path" };
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd } = await gitRepo();
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: `git+https://github.com/${owner}/${packageName}` },
release: { extends: "./shareable.json", success: false, fail: false },
});
await writeJson(path.resolve(cwd, "shareable.json"), shareable);
const { exitCode, stderr } = await t.throwsAsync(execa(cli, [], { env, cwd, extendEnv: false }));
t.is(exitCode, 1);
t.regex(stderr, /Cannot find module/);
});
test("Dry-run", async (t) => {
const packageName = "test-dry-run";
const owner = "git";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
publishConfig: { registry: npmRegistry.url },
release: { success: false, fail: false },
});
/* Initial release */
const verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
const version = "1.0.0";
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release -d");
const { stdout, exitCode } = await execa(cli, ["-d"], { env, cwd, extendEnv: false });
t.regex(stdout, new RegExp(`There is no previous release, the next release version is ${version}`));
t.regex(stdout, new RegExp(`Release note for version ${version}`));
t.regex(stdout, /Initial commit/);
t.is(exitCode, 0);
// Verify package.json and has not been modified
t.is((await readJson(path.resolve(cwd, "package.json"))).version, "0.0.0-dev");
await mockServer.verify(verifyMock);
});
test('Allow local releases with "noCi" option', async (t) => {
const envNoCi = { ...env };
delete envNoCi.CI;
const packageName = "test-no-ci";
const owner = "git";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
publishConfig: { registry: npmRegistry.url },
release: { success: false, fail: false },
});
/* Initial release */
const version = "1.0.0";
const verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
const createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release --no-ci");
const { stdout, exitCode } = await execa(cli, ["--no-ci"], { env: envNoCi, cwd, extendEnv: false });
t.regex(stdout, new RegExp(`Published GitHub release: release-url/${version}`));
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and has been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv);
const head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(releasedGitHead, head);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
});
test("Pass options via CLI arguments", async (t) => {
const packageName = "test-cli";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
publishConfig: { registry: npmRegistry.url },
});
/* Initial release */
const version = "1.0.0";
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release");
const { stdout, exitCode } = await execa(
cli,
[
"--verify-conditions",
"@semantic-release/npm",
"--publish",
"@semantic-release/npm",
`--success`,
false,
`--fail`,
false,
"--debug",
],
{ env, cwd, extendEnv: false }
);
t.regex(stdout, new RegExp(`Publishing version ${version} to npm registry`));
t.is(exitCode, 0);
// Verify package.json and has been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv);
const head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(releasedGitHead, head);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`);
});
test("Run via JS API", async (t) => {
td.replace("../lib/logger", { log: () => {}, error: () => {}, stdout: () => {} });
td.replace("env-ci", () => ({ isCi: true, branch: "master", isPr: false }));
const semanticRelease = (await import("../index.js")).default;
const packageName = "test-js-api";
const owner = "git";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl, authUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
publishConfig: { registry: npmRegistry.url },
release: {
fail: false,
success: false,
},
});
/* Initial release */
const version = "1.0.0";
const verifyMock = await mockServer.mock(
`/repos/${owner}/${packageName}`,
{ headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }] },
{ body: { permissions: { push: true } }, method: "GET" }
);
const createReleaseMock = await mockServer.mock(
`/repos/${owner}/${packageName}/releases`,
{
body: { tag_name: `v${version}`, name: `v${version}` },
headers: [{ name: "Authorization", values: [`token ${env.GH_TOKEN}`] }],
},
{ body: { html_url: `release-url/${version}` } }
);
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ Call semantic-release via API");
await semanticRelease(undefined, {
cwd,
env,
stdout: new WritableStreamBuffer(),
stderr: new WritableStreamBuffer(),
});
// Verify package.json and has been updated
t.is((await readJson(path.resolve(cwd, "package.json"))).version, version);
// Retrieve the published package from the registry and check version and gitHead
const { version: releasedVersion, gitHead: releasedGitHead } = await npmView(packageName, npmTestEnv);
const head = await gitHead({ cwd });
t.is(releasedVersion, version);
t.is(releasedGitHead, head);
t.is(await gitTagHead(`v${version}`, { cwd }), head);
t.is(await gitRemoteTagHead(authUrl, `v${version}`, { cwd }), head);
t.log(`+ released ${releasedVersion} with head ${releasedGitHead}`);
await mockServer.verify(verifyMock);
await mockServer.verify(createReleaseMock);
});
test("Log unexpected errors from plugins and exit with 1", async (t) => {
const packageName = "test-unexpected-error";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
release: { verifyConditions: pluginError, fail: false, success: false },
});
/* Initial release */
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release");
const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false });
// Verify the type and message are logged
t.regex(stderr, /Error: a/);
// Verify the the stacktrace is logged
t.regex(stderr, new RegExp(pluginError));
// Verify the Error properties are logged
t.regex(stderr, /errorProperty: 'errorProperty'/);
t.is(exitCode, 1);
});
test("Log errors inheriting SemanticReleaseError and exit with 1", async (t) => {
const packageName = "test-inherited-error";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository and package.json");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);
// Create package.json in repository root
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
release: { verifyConditions: pluginInheritedError, fail: false, success: false },
});
/* Initial release */
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
t.log("$ semantic-release");
const { stderr, exitCode } = await execa(cli, [], { env, cwd, reject: false, extendEnv: false });
// Verify the type and message are logged
t.regex(stderr, /EINHERITED Inherited error/);
t.is(exitCode, 1);
});
test("Exit with 1 if missing permission to push to the remote repository", async (t) => {
const packageName = "unauthorized";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd } = await gitbox.createRepo(packageName);
await writeJson(path.resolve(cwd, "package.json"), { name: packageName, version: "0.0.0-dev" });
/* Initial release */
t.log("Commit a feature");
await gitCommits(["feat: Initial commit"], { cwd });
await gitPush("origin", "master", { cwd });
t.log("$ semantic-release");
const { stderr, exitCode } = await execa(
cli,
["--repository-url", "http://user:wrong_pass@localhost:2080/git/unauthorized.git"],
{ env: { ...env, GH_TOKEN: "user:wrong_pass" }, cwd, reject: false, extendEnv: false }
);
// Verify the type and message are logged
t.regex(stderr, /EGITNOPERMISSION/);
t.is(exitCode, 1);
});
test("Hide sensitive environment variable values from the logs", async (t) => {
const packageName = "log-secret";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
release: { verifyConditions: [pluginLogEnv], fail: false, success: false },
});
t.log("$ semantic-release");
const { stdout, stderr } = await execa(cli, [], {
env: { ...env, MY_TOKEN: "secret token" },
cwd,
reject: false,
extendEnv: false,
});
t.regex(stdout, new RegExp(`Console: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`));
t.regex(stdout, new RegExp(`Log: Exposing token ${escapeRegExp(SECRET_REPLACEMENT)}`));
t.regex(stderr, new RegExp(`Error: Console token ${escapeRegExp(SECRET_REPLACEMENT)}`));
t.regex(stderr, new RegExp(`Throw error: Exposing ${escapeRegExp(SECRET_REPLACEMENT)}`));
});
test("Use the valid git credentials when multiple are provided", async (t) => {
const { cwd, authUrl } = await gitbox.createRepo("test-auth");
t.is(
await getAuthUrl({
cwd,
env: {
GITHUB_TOKEN: "dummy",
GITLAB_TOKEN: "trash",
BB_TOKEN_BASIC_AUTH: gitbox.gitCredential,
GIT_ASKPASS: "echo",
GIT_TERMINAL_PROMPT: 0,
},
branch: { name: "master" },
options: { repositoryUrl: "http://toto@localhost:2080/git/test-auth.git" },
}),
authUrl
);
});
test("Use the repository URL as is if none of the given git credentials are valid", async (t) => {
const { cwd } = await gitbox.createRepo("test-invalid-auth");
const dummyUrl = "http://toto@localhost:2080/git/test-invalid-auth.git";
t.is(
await getAuthUrl({
cwd,
env: {
GITHUB_TOKEN: "dummy",
GITLAB_TOKEN: "trash",
GIT_ASKPASS: "echo",
GIT_TERMINAL_PROMPT: 0,
},
branch: { name: "master" },
options: { repositoryUrl: dummyUrl },
}),
dummyUrl
);
});
test("ESM Plugin with named exports", async (t) => {
const packageName = "log-secret";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);
await writeJson(path.resolve(cwd, "package.json"), {
name: packageName,
version: "0.0.0-dev",
repository: { url: repositoryUrl },
release: { plugins: [pluginEsmNamedExports] },
});
t.log("$ semantic-release");
const { stdout, stderr } = await execa(cli, [], {
env: { ...env, MY_TOKEN: "secret token" },
cwd,
reject: false,
extendEnv: false,
});
t.regex(stdout, new RegExp(`verifyConditions called`));
});