semantic-release 20.0.0-beta.3 → 20.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/bin/semantic-release.js +9 -9
- package/cli.js +31 -31
- package/docs/developer-guide/js-api.md +46 -37
- package/docs/developer-guide/plugin.md +97 -93
- package/docs/extending/plugins-list.md +8 -7
- package/docs/extending/shareable-configurations-list.md +2 -0
- package/docs/recipes/ci-configurations/README.md +1 -0
- package/docs/recipes/ci-configurations/github-actions.md +6 -3
- package/docs/recipes/ci-configurations/gitlab-ci.md +2 -3
- package/docs/recipes/git-hosted-services/README.md +1 -0
- package/docs/recipes/git-hosted-services/git-auth-ssh-keys.md +4 -1
- package/docs/recipes/release-workflow/README.md +1 -0
- package/docs/recipes/release-workflow/distribution-channels.md +1 -0
- package/docs/recipes/release-workflow/maintenance-releases.md +1 -0
- package/docs/recipes/release-workflow/pre-releases.md +1 -0
- package/docs/support/FAQ.md +25 -14
- package/docs/support/troubleshooting.md +1 -0
- package/docs/usage/ci-configuration.md +4 -3
- package/docs/usage/configuration.md +8 -2
- package/docs/usage/plugins.md +11 -5
- package/docs/usage/workflow-configuration.md +29 -17
- package/index.js +75 -72
- package/lib/get-commits.js +15 -9
- package/lib/get-config.js +38 -38
- package/lib/get-error.js +4 -4
- package/lib/get-git-auth-url.js +32 -32
- package/lib/get-last-release.js +8 -8
- package/lib/get-logger.js +10 -10
- package/lib/get-next-version.js +11 -11
- package/lib/get-release-to-add.js +17 -17
- package/lib/git.js +41 -41
- package/lib/hide-sensitive.js +6 -6
- package/lib/utils.js +12 -12
- package/lib/verify.js +14 -14
- package/package.json +6 -13
package/lib/get-git-auth-url.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {format, parse} from
|
|
2
|
-
import {isNil} from
|
|
3
|
-
import hostedGitInfo from
|
|
4
|
-
import debugAuthUrl from
|
|
5
|
-
import {verifyAuth} from
|
|
1
|
+
import { format, parse } from "node:url";
|
|
2
|
+
import { isNil } from "lodash-es";
|
|
3
|
+
import hostedGitInfo from "hosted-git-info";
|
|
4
|
+
import debugAuthUrl from "debug";
|
|
5
|
+
import { verifyAuth } from "./git.js";
|
|
6
6
|
|
|
7
|
-
const debug = debugAuthUrl(
|
|
7
|
+
const debug = debugAuthUrl("semantic-release:get-git-auth-url");
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Machinery to format a repository URL with the given credentials
|
|
@@ -18,15 +18,15 @@ const debug = debugAuthUrl('semantic-release:get-git-auth-url');
|
|
|
18
18
|
function formatAuthUrl(protocol, repositoryUrl, gitCredentials) {
|
|
19
19
|
const [match, auth, host, basePort, path] =
|
|
20
20
|
/^(?!.+:\/\/)(?:(?<auth>.*)@)?(?<host>.*?):(?<port>\d+)?:?\/?(?<path>.*)$/.exec(repositoryUrl) || [];
|
|
21
|
-
const {port, hostname, ...parsed} = parse(
|
|
22
|
-
match ? `ssh://${auth ? `${auth}@` :
|
|
21
|
+
const { port, hostname, ...parsed } = parse(
|
|
22
|
+
match ? `ssh://${auth ? `${auth}@` : ""}${host}${basePort ? `:${basePort}` : ""}/${path}` : repositoryUrl
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
return format({
|
|
26
26
|
...parsed,
|
|
27
27
|
auth: gitCredentials,
|
|
28
|
-
host: `${hostname}${protocol ===
|
|
29
|
-
protocol: protocol && /http[^s]/.test(protocol) ?
|
|
28
|
+
host: `${hostname}${protocol === "ssh:" ? "" : port ? `:${port}` : ""}`,
|
|
29
|
+
protocol: protocol && /http[^s]/.test(protocol) ? "http" : "https",
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -38,9 +38,9 @@ function formatAuthUrl(protocol, repositoryUrl, gitCredentials) {
|
|
|
38
38
|
*
|
|
39
39
|
* @return {String} The authUrl as is if the connection was successfull, null otherwise
|
|
40
40
|
*/
|
|
41
|
-
async function ensureValidAuthUrl({cwd, env, branch}, authUrl) {
|
|
41
|
+
async function ensureValidAuthUrl({ cwd, env, branch }, authUrl) {
|
|
42
42
|
try {
|
|
43
|
-
await verifyAuth(authUrl, branch.name, {cwd, env});
|
|
43
|
+
await verifyAuth(authUrl, branch.name, { cwd, env });
|
|
44
44
|
return authUrl;
|
|
45
45
|
} catch (error) {
|
|
46
46
|
debug(error);
|
|
@@ -60,44 +60,44 @@ async function ensureValidAuthUrl({cwd, env, branch}, authUrl) {
|
|
|
60
60
|
* @return {String} The formatted Git repository URL.
|
|
61
61
|
*/
|
|
62
62
|
export default async (context) => {
|
|
63
|
-
const {cwd, env, branch} = context;
|
|
63
|
+
const { cwd, env, branch } = context;
|
|
64
64
|
const GIT_TOKENS = {
|
|
65
65
|
GIT_CREDENTIALS: undefined,
|
|
66
66
|
GH_TOKEN: undefined,
|
|
67
67
|
// GitHub Actions require the "x-access-token:" prefix for git access
|
|
68
68
|
// https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#http-based-git-access-by-an-installation
|
|
69
|
-
GITHUB_TOKEN: isNil(env.GITHUB_ACTION) ? undefined :
|
|
70
|
-
GL_TOKEN:
|
|
71
|
-
GITLAB_TOKEN:
|
|
72
|
-
BB_TOKEN:
|
|
73
|
-
BITBUCKET_TOKEN:
|
|
74
|
-
BB_TOKEN_BASIC_AUTH:
|
|
75
|
-
BITBUCKET_TOKEN_BASIC_AUTH:
|
|
69
|
+
GITHUB_TOKEN: isNil(env.GITHUB_ACTION) ? undefined : "x-access-token:",
|
|
70
|
+
GL_TOKEN: "gitlab-ci-token:",
|
|
71
|
+
GITLAB_TOKEN: "gitlab-ci-token:",
|
|
72
|
+
BB_TOKEN: "x-token-auth:",
|
|
73
|
+
BITBUCKET_TOKEN: "x-token-auth:",
|
|
74
|
+
BB_TOKEN_BASIC_AUTH: "",
|
|
75
|
+
BITBUCKET_TOKEN_BASIC_AUTH: "",
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
let {repositoryUrl} = context.options;
|
|
79
|
-
const info = hostedGitInfo.fromUrl(repositoryUrl, {noGitPlus: true});
|
|
80
|
-
const {protocol, ...parsed} = parse(repositoryUrl);
|
|
78
|
+
let { repositoryUrl } = context.options;
|
|
79
|
+
const info = hostedGitInfo.fromUrl(repositoryUrl, { noGitPlus: true });
|
|
80
|
+
const { protocol, ...parsed } = parse(repositoryUrl);
|
|
81
81
|
|
|
82
|
-
if (info && info.getDefaultRepresentation() ===
|
|
82
|
+
if (info && info.getDefaultRepresentation() === "shortcut") {
|
|
83
83
|
// Expand shorthand URLs (such as `owner/repo` or `gitlab:owner/repo`)
|
|
84
84
|
repositoryUrl = info.https();
|
|
85
|
-
} else if (protocol && protocol.includes(
|
|
85
|
+
} else if (protocol && protocol.includes("http")) {
|
|
86
86
|
// Replace `git+https` and `git+http` with `https` or `http`
|
|
87
|
-
repositoryUrl = format({...parsed, protocol: protocol.includes(
|
|
87
|
+
repositoryUrl = format({ ...parsed, protocol: protocol.includes("https") ? "https" : "http", href: null });
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// Test if push is allowed without transforming the URL (e.g. is ssh keys are set up)
|
|
91
91
|
try {
|
|
92
|
-
debug(
|
|
93
|
-
await verifyAuth(repositoryUrl, branch.name, {cwd, env});
|
|
92
|
+
debug("Verifying ssh auth by attempting to push to %s", repositoryUrl);
|
|
93
|
+
await verifyAuth(repositoryUrl, branch.name, { cwd, env });
|
|
94
94
|
} catch {
|
|
95
|
-
debug(
|
|
95
|
+
debug("SSH key auth failed, falling back to https.");
|
|
96
96
|
const envVars = Object.keys(GIT_TOKENS).filter((envVar) => !isNil(env[envVar]));
|
|
97
97
|
|
|
98
98
|
// Skip verification if there is no ambiguity on which env var to use for authentication
|
|
99
99
|
if (envVars.length === 1) {
|
|
100
|
-
const gitCredentials = `${GIT_TOKENS[envVars[0]] ||
|
|
100
|
+
const gitCredentials = `${GIT_TOKENS[envVars[0]] || ""}${env[envVars[0]]}`;
|
|
101
101
|
return formatAuthUrl(protocol, repositoryUrl, gitCredentials);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -106,7 +106,7 @@ export default async (context) => {
|
|
|
106
106
|
|
|
107
107
|
const candidateRepositoryUrls = [];
|
|
108
108
|
for (const envVar of envVars) {
|
|
109
|
-
const gitCredentials = `${GIT_TOKENS[envVar] ||
|
|
109
|
+
const gitCredentials = `${GIT_TOKENS[envVar] || ""}${env[envVar]}`;
|
|
110
110
|
const authUrl = formatAuthUrl(protocol, repositoryUrl, gitCredentials);
|
|
111
111
|
candidateRepositoryUrls.push(ensureValidAuthUrl(context, authUrl));
|
|
112
112
|
}
|
|
@@ -121,4 +121,4 @@ export default async (context) => {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
return repositoryUrl;
|
|
124
|
-
}
|
|
124
|
+
};
|
package/lib/get-last-release.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {isUndefined} from
|
|
2
|
-
import semver from
|
|
3
|
-
import {isSameChannel, makeTag} from
|
|
1
|
+
import { isUndefined } from "lodash-es";
|
|
2
|
+
import semver from "semver";
|
|
3
|
+
import { isSameChannel, makeTag } from "./utils.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Last release.
|
|
@@ -26,19 +26,19 @@ import {isSameChannel, makeTag} from './utils.js';
|
|
|
26
26
|
*
|
|
27
27
|
* @return {LastRelease} The last tagged release or empty object if none is found.
|
|
28
28
|
*/
|
|
29
|
-
export default ({branch, options: {tagFormat}}, {before} = {}) => {
|
|
30
|
-
const [{version, gitTag, channels} = {}] = branch.tags
|
|
29
|
+
export default ({ branch, options: { tagFormat } }, { before } = {}) => {
|
|
30
|
+
const [{ version, gitTag, channels } = {}] = branch.tags
|
|
31
31
|
.filter(
|
|
32
32
|
(tag) =>
|
|
33
|
-
((branch.type ===
|
|
33
|
+
((branch.type === "prerelease" && tag.channels.some((channel) => isSameChannel(branch.channel, channel))) ||
|
|
34
34
|
!semver.prerelease(tag.version)) &&
|
|
35
35
|
(isUndefined(before) || semver.lt(tag.version, before))
|
|
36
36
|
)
|
|
37
37
|
.sort((a, b) => semver.rcompare(a.version, b.version));
|
|
38
38
|
|
|
39
39
|
if (gitTag) {
|
|
40
|
-
return {version, gitTag, channels, gitHead: gitTag, name: makeTag(tagFormat, version)};
|
|
40
|
+
return { version, gitTag, channels, gitHead: gitTag, name: makeTag(tagFormat, version) };
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
return {};
|
|
44
|
-
}
|
|
44
|
+
};
|
package/lib/get-logger.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import signale from
|
|
2
|
-
import figures from
|
|
1
|
+
import signale from "signale";
|
|
2
|
+
import figures from "figures";
|
|
3
3
|
|
|
4
|
-
const {Signale} = signale;
|
|
4
|
+
const { Signale } = signale;
|
|
5
5
|
|
|
6
|
-
export default ({stdout, stderr}) =>
|
|
6
|
+
export default ({ stdout, stderr }) =>
|
|
7
7
|
new Signale({
|
|
8
|
-
config: {displayTimestamp: true, underlineMessage: false, displayLabel: false},
|
|
8
|
+
config: { displayTimestamp: true, underlineMessage: false, displayLabel: false },
|
|
9
9
|
disabled: false,
|
|
10
10
|
interactive: false,
|
|
11
|
-
scope:
|
|
11
|
+
scope: "semantic-release",
|
|
12
12
|
stream: [stdout],
|
|
13
13
|
types: {
|
|
14
|
-
error: {badge: figures.cross, color:
|
|
15
|
-
log: {badge: figures.info, color:
|
|
16
|
-
success: {badge: figures.tick, color:
|
|
14
|
+
error: { badge: figures.cross, color: "red", label: "", stream: [stderr] },
|
|
15
|
+
log: { badge: figures.info, color: "magenta", label: "", stream: [stdout] },
|
|
16
|
+
success: { badge: figures.tick, color: "green", label: "", stream: [stdout] },
|
|
17
17
|
},
|
|
18
|
-
})
|
|
18
|
+
});
|
package/lib/get-next-version.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import semver from
|
|
2
|
-
import {FIRST_RELEASE, FIRSTPRERELEASE} from
|
|
3
|
-
import {getLatestVersion, highest, isSameChannel, tagsToVersions} from
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { FIRST_RELEASE, FIRSTPRERELEASE } from "./definitions/constants.js";
|
|
3
|
+
import { getLatestVersion, highest, isSameChannel, tagsToVersions } from "./utils.js";
|
|
4
4
|
|
|
5
|
-
export default ({branch, nextRelease: {type, channel}, lastRelease, logger}) => {
|
|
5
|
+
export default ({ branch, nextRelease: { type, channel }, lastRelease, logger }) => {
|
|
6
6
|
let version;
|
|
7
7
|
if (lastRelease.version) {
|
|
8
|
-
const {major, minor, patch} = semver.parse(lastRelease.version);
|
|
8
|
+
const { major, minor, patch } = semver.parse(lastRelease.version);
|
|
9
9
|
|
|
10
|
-
if (branch.type ===
|
|
10
|
+
if (branch.type === "prerelease") {
|
|
11
11
|
if (
|
|
12
12
|
semver.prerelease(lastRelease.version) &&
|
|
13
13
|
lastRelease.channels.some((lastReleaseChannel) => isSameChannel(lastReleaseChannel, channel))
|
|
14
14
|
) {
|
|
15
15
|
version = highest(
|
|
16
|
-
semver.inc(lastRelease.version,
|
|
17
|
-
`${semver.inc(getLatestVersion(tagsToVersions(branch.tags), {withPrerelease: true}), type)}-${
|
|
16
|
+
semver.inc(lastRelease.version, "prerelease"),
|
|
17
|
+
`${semver.inc(getLatestVersion(tagsToVersions(branch.tags), { withPrerelease: true }), type)}-${
|
|
18
18
|
branch.prerelease
|
|
19
19
|
}.${FIRSTPRERELEASE}`
|
|
20
20
|
);
|
|
@@ -25,11 +25,11 @@ export default ({branch, nextRelease: {type, channel}, lastRelease, logger}) =>
|
|
|
25
25
|
version = semver.inc(lastRelease.version, type);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
logger.log(
|
|
28
|
+
logger.log("The next release version is %s", version);
|
|
29
29
|
} else {
|
|
30
|
-
version = branch.type ===
|
|
30
|
+
version = branch.type === "prerelease" ? `${FIRST_RELEASE}-${branch.prerelease}.${FIRSTPRERELEASE}` : FIRST_RELEASE;
|
|
31
31
|
logger.log(`There is no previous release, the next release version is ${version}`);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return version;
|
|
35
|
-
}
|
|
35
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {intersection, uniqBy} from
|
|
2
|
-
import semver from
|
|
3
|
-
import semverDiff from
|
|
4
|
-
import getLastRelease from
|
|
5
|
-
import {getLowerBound, makeTag} from
|
|
1
|
+
import { intersection, uniqBy } from "lodash-es";
|
|
2
|
+
import semver from "semver";
|
|
3
|
+
import semverDiff from "semver-diff";
|
|
4
|
+
import getLastRelease from "./get-last-release.js";
|
|
5
|
+
import { getLowerBound, makeTag } from "./utils.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Find releases that have been merged from from a higher branch but not added on the channel of the current branch.
|
|
@@ -15,38 +15,38 @@ export default (context) => {
|
|
|
15
15
|
const {
|
|
16
16
|
branch,
|
|
17
17
|
branches,
|
|
18
|
-
options: {tagFormat},
|
|
18
|
+
options: { tagFormat },
|
|
19
19
|
} = context;
|
|
20
20
|
|
|
21
21
|
const higherChannels = branches
|
|
22
22
|
// Consider only releases of higher branches
|
|
23
|
-
.slice(branches.findIndex(({name}) => name === branch.name) + 1)
|
|
23
|
+
.slice(branches.findIndex(({ name }) => name === branch.name) + 1)
|
|
24
24
|
// Exclude prerelease branches
|
|
25
|
-
.filter(({type}) => type !==
|
|
26
|
-
.map(({channel}) => channel || null);
|
|
25
|
+
.filter(({ type }) => type !== "prerelease")
|
|
26
|
+
.map(({ channel }) => channel || null);
|
|
27
27
|
|
|
28
28
|
const versiontoAdd = uniqBy(
|
|
29
29
|
branch.tags.filter(
|
|
30
|
-
({channels, version}) =>
|
|
30
|
+
({ channels, version }) =>
|
|
31
31
|
!channels.includes(branch.channel || null) &&
|
|
32
32
|
intersection(channels, higherChannels).length > 0 &&
|
|
33
|
-
(branch.type !==
|
|
33
|
+
(branch.type !== "maintenance" || semver.gte(version, getLowerBound(branch.mergeRange)))
|
|
34
34
|
),
|
|
35
|
-
|
|
35
|
+
"version"
|
|
36
36
|
).sort((a, b) => semver.compare(b.version, a.version))[0];
|
|
37
37
|
|
|
38
38
|
if (versiontoAdd) {
|
|
39
|
-
const {version, gitTag, channels} = versiontoAdd;
|
|
40
|
-
const lastRelease = getLastRelease(context, {before: version});
|
|
39
|
+
const { version, gitTag, channels } = versiontoAdd;
|
|
40
|
+
const lastRelease = getLastRelease(context, { before: version });
|
|
41
41
|
if (semver.gt(getLastRelease(context).version, version)) {
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const type = lastRelease.version ? semverDiff(lastRelease.version, version) :
|
|
45
|
+
const type = lastRelease.version ? semverDiff(lastRelease.version, version) : "major";
|
|
46
46
|
const name = makeTag(tagFormat, version);
|
|
47
47
|
return {
|
|
48
48
|
lastRelease,
|
|
49
|
-
currentRelease: {type, version, channels, gitTag, name, gitHead: gitTag},
|
|
49
|
+
currentRelease: { type, version, channels, gitTag, name, gitHead: gitTag },
|
|
50
50
|
nextRelease: {
|
|
51
51
|
type,
|
|
52
52
|
version,
|
|
@@ -57,4 +57,4 @@ export default (context) => {
|
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
}
|
|
60
|
+
};
|
package/lib/git.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import gitLogParser from
|
|
2
|
-
import getStream from
|
|
3
|
-
import {execa} from
|
|
4
|
-
import debugGit from
|
|
5
|
-
import {GIT_NOTE_REF} from
|
|
1
|
+
import gitLogParser from "git-log-parser";
|
|
2
|
+
import getStream from "get-stream";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
import debugGit from "debug";
|
|
5
|
+
import { GIT_NOTE_REF } from "./definitions/constants.js";
|
|
6
6
|
|
|
7
|
-
const debug = debugGit(
|
|
7
|
+
const debug = debugGit("semantic-release:git");
|
|
8
8
|
|
|
9
|
-
Object.assign(gitLogParser.fields, {hash:
|
|
9
|
+
Object.assign(gitLogParser.fields, { hash: "H", message: "B", gitTags: "d", committerDate: { key: "ci", type: Date } });
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Get the commit sha for a given tag.
|
|
@@ -17,7 +17,7 @@ Object.assign(gitLogParser.fields, {hash: 'H', message: 'B', gitTags: 'd', commi
|
|
|
17
17
|
* @return {String} The commit sha of the tag in parameter or `null`.
|
|
18
18
|
*/
|
|
19
19
|
export async function getTagHead(tagName, execaOptions) {
|
|
20
|
-
return (await execa(
|
|
20
|
+
return (await execa("git", ["rev-list", "-1", tagName], execaOptions)).stdout;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -30,8 +30,8 @@ export async function getTagHead(tagName, execaOptions) {
|
|
|
30
30
|
* @throws {Error} If the `git` command fails.
|
|
31
31
|
*/
|
|
32
32
|
export async function getTags(branch, execaOptions) {
|
|
33
|
-
return (await execa(
|
|
34
|
-
.split(
|
|
33
|
+
return (await execa("git", ["tag", "--merged", branch], execaOptions)).stdout
|
|
34
|
+
.split("\n")
|
|
35
35
|
.map((tag) => tag.trim())
|
|
36
36
|
.filter(Boolean);
|
|
37
37
|
}
|
|
@@ -48,11 +48,11 @@ export async function getCommits(from, to, execaOptions) {
|
|
|
48
48
|
return (
|
|
49
49
|
await getStream.array(
|
|
50
50
|
gitLogParser.parse(
|
|
51
|
-
{_: `${from ? from +
|
|
52
|
-
{cwd: execaOptions.cwd, env: {...process.env, ...execaOptions.env}}
|
|
51
|
+
{ _: `${from ? from + ".." : ""}${to}` },
|
|
52
|
+
{ cwd: execaOptions.cwd, env: { ...process.env, ...execaOptions.env } }
|
|
53
53
|
)
|
|
54
54
|
)
|
|
55
|
-
).map(({message, gitTags, ...commit}) => ({...commit, message: message.trim(), gitTags: gitTags.trim()}));
|
|
55
|
+
).map(({ message, gitTags, ...commit }) => ({ ...commit, message: message.trim(), gitTags: gitTags.trim() }));
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -65,8 +65,8 @@ export async function getCommits(from, to, execaOptions) {
|
|
|
65
65
|
* @throws {Error} If the `git` command fails.
|
|
66
66
|
*/
|
|
67
67
|
export async function getBranches(repositoryUrl, execaOptions) {
|
|
68
|
-
return (await execa(
|
|
69
|
-
.split(
|
|
68
|
+
return (await execa("git", ["ls-remote", "--heads", repositoryUrl], execaOptions)).stdout
|
|
69
|
+
.split("\n")
|
|
70
70
|
.filter(Boolean)
|
|
71
71
|
.map((branch) => branch.match(/^.+refs\/heads\/(?<branch>.+)$/)[1]);
|
|
72
72
|
}
|
|
@@ -81,7 +81,7 @@ export async function getBranches(repositoryUrl, execaOptions) {
|
|
|
81
81
|
*/
|
|
82
82
|
export async function isRefExists(ref, execaOptions) {
|
|
83
83
|
try {
|
|
84
|
-
return (await execa(
|
|
84
|
+
return (await execa("git", ["rev-parse", "--verify", ref], execaOptions)).exitCode === 0;
|
|
85
85
|
} catch (error) {
|
|
86
86
|
debug(error);
|
|
87
87
|
}
|
|
@@ -103,30 +103,30 @@ export async function isRefExists(ref, execaOptions) {
|
|
|
103
103
|
*/
|
|
104
104
|
export async function fetch(repositoryUrl, branch, ciBranch, execaOptions) {
|
|
105
105
|
const isDetachedHead =
|
|
106
|
-
(await execa(
|
|
106
|
+
(await execa("git", ["rev-parse", "--abbrev-ref", "HEAD"], { ...execaOptions, reject: false })).stdout === "HEAD";
|
|
107
107
|
|
|
108
108
|
try {
|
|
109
109
|
await execa(
|
|
110
|
-
|
|
110
|
+
"git",
|
|
111
111
|
[
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
"fetch",
|
|
113
|
+
"--unshallow",
|
|
114
|
+
"--tags",
|
|
115
115
|
...(branch === ciBranch && !isDetachedHead
|
|
116
116
|
? [repositoryUrl]
|
|
117
|
-
: [
|
|
117
|
+
: ["--update-head-ok", repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
|
|
118
118
|
],
|
|
119
119
|
execaOptions
|
|
120
120
|
);
|
|
121
121
|
} catch {
|
|
122
122
|
await execa(
|
|
123
|
-
|
|
123
|
+
"git",
|
|
124
124
|
[
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
"fetch",
|
|
126
|
+
"--tags",
|
|
127
127
|
...(branch === ciBranch && !isDetachedHead
|
|
128
128
|
? [repositoryUrl]
|
|
129
|
-
: [
|
|
129
|
+
: ["--update-head-ok", repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
|
|
130
130
|
],
|
|
131
131
|
execaOptions
|
|
132
132
|
);
|
|
@@ -142,12 +142,12 @@ export async function fetch(repositoryUrl, branch, ciBranch, execaOptions) {
|
|
|
142
142
|
export async function fetchNotes(repositoryUrl, execaOptions) {
|
|
143
143
|
try {
|
|
144
144
|
await execa(
|
|
145
|
-
|
|
146
|
-
[
|
|
145
|
+
"git",
|
|
146
|
+
["fetch", "--unshallow", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`],
|
|
147
147
|
execaOptions
|
|
148
148
|
);
|
|
149
149
|
} catch {
|
|
150
|
-
await execa(
|
|
150
|
+
await execa("git", ["fetch", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`], {
|
|
151
151
|
...execaOptions,
|
|
152
152
|
reject: false,
|
|
153
153
|
});
|
|
@@ -162,7 +162,7 @@ export async function fetchNotes(repositoryUrl, execaOptions) {
|
|
|
162
162
|
* @return {String} the sha of the HEAD commit.
|
|
163
163
|
*/
|
|
164
164
|
export async function getGitHead(execaOptions) {
|
|
165
|
-
return (await execa(
|
|
165
|
+
return (await execa("git", ["rev-parse", "HEAD"], execaOptions)).stdout;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
@@ -174,7 +174,7 @@ export async function getGitHead(execaOptions) {
|
|
|
174
174
|
*/
|
|
175
175
|
export async function repoUrl(execaOptions) {
|
|
176
176
|
try {
|
|
177
|
-
return (await execa(
|
|
177
|
+
return (await execa("git", ["config", "--get", "remote.origin.url"], execaOptions)).stdout;
|
|
178
178
|
} catch (error) {
|
|
179
179
|
debug(error);
|
|
180
180
|
}
|
|
@@ -189,7 +189,7 @@ export async function repoUrl(execaOptions) {
|
|
|
189
189
|
*/
|
|
190
190
|
export async function isGitRepo(execaOptions) {
|
|
191
191
|
try {
|
|
192
|
-
return (await execa(
|
|
192
|
+
return (await execa("git", ["rev-parse", "--git-dir"], execaOptions)).exitCode === 0;
|
|
193
193
|
} catch (error) {
|
|
194
194
|
debug(error);
|
|
195
195
|
}
|
|
@@ -206,7 +206,7 @@ export async function isGitRepo(execaOptions) {
|
|
|
206
206
|
*/
|
|
207
207
|
export async function verifyAuth(repositoryUrl, branch, execaOptions) {
|
|
208
208
|
try {
|
|
209
|
-
await execa(
|
|
209
|
+
await execa("git", ["push", "--dry-run", "--no-verify", repositoryUrl, `HEAD:${branch}`], execaOptions);
|
|
210
210
|
} catch (error) {
|
|
211
211
|
debug(error);
|
|
212
212
|
throw error;
|
|
@@ -223,7 +223,7 @@ export async function verifyAuth(repositoryUrl, branch, execaOptions) {
|
|
|
223
223
|
* @throws {Error} if the tag creation failed.
|
|
224
224
|
*/
|
|
225
225
|
export async function tag(tagName, ref, execaOptions) {
|
|
226
|
-
await execa(
|
|
226
|
+
await execa("git", ["tag", tagName, ref], execaOptions);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
/**
|
|
@@ -235,7 +235,7 @@ export async function tag(tagName, ref, execaOptions) {
|
|
|
235
235
|
* @throws {Error} if the push failed.
|
|
236
236
|
*/
|
|
237
237
|
export async function push(repositoryUrl, execaOptions) {
|
|
238
|
-
await execa(
|
|
238
|
+
await execa("git", ["push", "--tags", repositoryUrl], execaOptions);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
@@ -247,7 +247,7 @@ export async function push(repositoryUrl, execaOptions) {
|
|
|
247
247
|
* @throws {Error} if the push failed.
|
|
248
248
|
*/
|
|
249
249
|
export async function pushNotes(repositoryUrl, execaOptions) {
|
|
250
|
-
await execa(
|
|
250
|
+
await execa("git", ["push", repositoryUrl, `refs/notes/${GIT_NOTE_REF}`], execaOptions);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
/**
|
|
@@ -260,7 +260,7 @@ export async function pushNotes(repositoryUrl, execaOptions) {
|
|
|
260
260
|
*/
|
|
261
261
|
export async function verifyTagName(tagName, execaOptions) {
|
|
262
262
|
try {
|
|
263
|
-
return (await execa(
|
|
263
|
+
return (await execa("git", ["check-ref-format", `refs/tags/${tagName}`], execaOptions)).exitCode === 0;
|
|
264
264
|
} catch (error) {
|
|
265
265
|
debug(error);
|
|
266
266
|
}
|
|
@@ -276,7 +276,7 @@ export async function verifyTagName(tagName, execaOptions) {
|
|
|
276
276
|
*/
|
|
277
277
|
export async function verifyBranchName(branch, execaOptions) {
|
|
278
278
|
try {
|
|
279
|
-
return (await execa(
|
|
279
|
+
return (await execa("git", ["check-ref-format", `refs/heads/${branch}`], execaOptions)).exitCode === 0;
|
|
280
280
|
} catch (error) {
|
|
281
281
|
debug(error);
|
|
282
282
|
}
|
|
@@ -294,7 +294,7 @@ export async function verifyBranchName(branch, execaOptions) {
|
|
|
294
294
|
export async function isBranchUpToDate(repositoryUrl, branch, execaOptions) {
|
|
295
295
|
return (
|
|
296
296
|
(await getGitHead(execaOptions)) ===
|
|
297
|
-
(await execa(
|
|
297
|
+
(await execa("git", ["ls-remote", "--heads", repositoryUrl, branch], execaOptions)).stdout.match(/^(?<ref>\w+)?/)[1]
|
|
298
298
|
);
|
|
299
299
|
}
|
|
300
300
|
|
|
@@ -308,7 +308,7 @@ export async function isBranchUpToDate(repositoryUrl, branch, execaOptions) {
|
|
|
308
308
|
*/
|
|
309
309
|
export async function getNote(ref, execaOptions) {
|
|
310
310
|
try {
|
|
311
|
-
return JSON.parse((await execa(
|
|
311
|
+
return JSON.parse((await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions)).stdout);
|
|
312
312
|
} catch (error) {
|
|
313
313
|
if (error.exitCode === 1) {
|
|
314
314
|
return {};
|
|
@@ -327,5 +327,5 @@ export async function getNote(ref, execaOptions) {
|
|
|
327
327
|
* @param {Object} [execaOpts] Options to pass to `execa`.
|
|
328
328
|
*/
|
|
329
329
|
export async function addNote(note, ref, execaOptions) {
|
|
330
|
-
await execa(
|
|
330
|
+
await execa("git", ["notes", "--ref", GIT_NOTE_REF, "add", "-f", "-m", JSON.stringify(note), ref], execaOptions);
|
|
331
331
|
}
|
package/lib/hide-sensitive.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {escapeRegExp, isString, size} from
|
|
2
|
-
import {SECRET_MIN_SIZE, SECRET_REPLACEMENT} from
|
|
1
|
+
import { escapeRegExp, isString, size } from "lodash-es";
|
|
2
|
+
import { SECRET_MIN_SIZE, SECRET_REPLACEMENT } from "./definitions/constants.js";
|
|
3
3
|
|
|
4
4
|
export default (env) => {
|
|
5
5
|
const toReplace = Object.keys(env).filter((envVar) => {
|
|
6
6
|
// https://github.com/semantic-release/semantic-release/issues/1558
|
|
7
|
-
if (envVar ===
|
|
7
|
+
if (envVar === "GOPRIVATE") {
|
|
8
8
|
return false;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -12,9 +12,9 @@ export default (env) => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
const regexp = new RegExp(
|
|
15
|
-
toReplace.map((envVar) => `${escapeRegExp(env[envVar])}|${escapeRegExp(encodeURI(env[envVar]))}`).join(
|
|
16
|
-
|
|
15
|
+
toReplace.map((envVar) => `${escapeRegExp(env[envVar])}|${escapeRegExp(encodeURI(env[envVar]))}`).join("|"),
|
|
16
|
+
"g"
|
|
17
17
|
);
|
|
18
18
|
return (output) =>
|
|
19
19
|
output && isString(output) && toReplace.length > 0 ? output.toString().replace(regexp, SECRET_REPLACEMENT) : output;
|
|
20
|
-
}
|
|
20
|
+
};
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {isFunction, template, union} from
|
|
2
|
-
import semver from
|
|
3
|
-
import hideSensitive from
|
|
1
|
+
import { isFunction, template, union } from "lodash-es";
|
|
2
|
+
import semver from "semver";
|
|
3
|
+
import hideSensitive from "./hide-sensitive.js";
|
|
4
4
|
|
|
5
5
|
export function extractErrors(err) {
|
|
6
6
|
return err && err.errors ? [...err.errors] : [err];
|
|
@@ -19,7 +19,7 @@ export function hideSensitiveValues(env, objs) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function tagsToVersions(tags) {
|
|
22
|
-
return tags.map(({version}) => version);
|
|
22
|
+
return tags.map(({ version }) => version);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function isMajorRange(range) {
|
|
@@ -33,16 +33,16 @@ export function isMaintenanceRange(range) {
|
|
|
33
33
|
export function getUpperBound(range) {
|
|
34
34
|
const result = semver.valid(range)
|
|
35
35
|
? range
|
|
36
|
-
: ((semver.validRange(range) ||
|
|
36
|
+
: ((semver.validRange(range) || "").match(/<(?<upperBound>\d+\.\d+\.\d+(-\d+)?)$/) || [])[1];
|
|
37
37
|
|
|
38
38
|
return result
|
|
39
39
|
? // https://github.com/npm/node-semver/issues/322
|
|
40
|
-
result.replace(/-\d+$/,
|
|
40
|
+
result.replace(/-\d+$/, "")
|
|
41
41
|
: result;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export function getLowerBound(range) {
|
|
45
|
-
return ((semver.validRange(range) ||
|
|
45
|
+
return ((semver.validRange(range) || "").match(/(?<lowerBound>\d+\.\d+\.\d+)/) || [])[1];
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function highest(version1, version2) {
|
|
@@ -53,16 +53,16 @@ export function lowest(version1, version2) {
|
|
|
53
53
|
return version1 && version2 ? (semver.lt(version1, version2) ? version1 : version2) : version1 || version2;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
export function getLatestVersion(versions, {withPrerelease} = {}) {
|
|
56
|
+
export function getLatestVersion(versions, { withPrerelease } = {}) {
|
|
57
57
|
return versions.filter((version) => withPrerelease || !semver.prerelease(version)).sort(semver.rcompare)[0];
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export function getEarliestVersion(versions, {withPrerelease} = {}) {
|
|
60
|
+
export function getEarliestVersion(versions, { withPrerelease } = {}) {
|
|
61
61
|
return versions.filter((version) => withPrerelease || !semver.prerelease(version)).sort(semver.compare)[0];
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function getFirstVersion(versions, lowerBranches) {
|
|
65
|
-
const lowerVersion = union(...lowerBranches.map(({tags}) => tagsToVersions(tags))).sort(semver.rcompare);
|
|
65
|
+
const lowerVersion = union(...lowerBranches.map(({ tags }) => tagsToVersions(tags))).sort(semver.rcompare);
|
|
66
66
|
if (lowerVersion[0]) {
|
|
67
67
|
return versions.sort(semver.compare).find((version) => semver.gt(version, lowerVersion[0]));
|
|
68
68
|
}
|
|
@@ -71,11 +71,11 @@ export function getFirstVersion(versions, lowerBranches) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
export function getRange(min, max) {
|
|
74
|
-
return `>=${min}${max ? ` <${max}` :
|
|
74
|
+
return `>=${min}${max ? ` <${max}` : ""}`;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export function makeTag(tagFormat, version) {
|
|
78
|
-
return template(tagFormat)({version});
|
|
78
|
+
return template(tagFormat)({ version });
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function isSameChannel(channel, otherChannel) {
|