Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ES Module #419

Merged
merged 39 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3ca59cf
refactor: replace `require` with `import`
gr2m Oct 1, 2021
a8d754a
style: xo
gr2m Oct 1, 2021
dcfce6b
refactor: use `lodash-es` instead of `lodash`
gr2m Oct 1, 2021
6c04ddf
build(deps): quibble
gr2m Oct 1, 2021
3044a32
test: adapt addChannel test
gr2m Oct 1, 2021
e2ee5e6
test: adapt fail test
gr2m Oct 1, 2021
0fbc003
test: adapt findIssues test
gr2m Oct 1, 2021
088ae45
test: adapt getClient test
gr2m Oct 1, 2021
942ddb2
test: adapt globAssets test
gr2m Oct 1, 2021
f2ad2f5
build(deps): -fs-extra
gr2m Oct 1, 2021
420f745
test: adapt publish test
gr2m Oct 1, 2021
d9087e1
test: adapt success test
gr2m Oct 2, 2021
bbe497d
test: adapt verify test
gr2m Oct 2, 2021
7c05697
test: adapt integration tests
gr2m Oct 2, 2021
c1d286b
test: disable linting for now because `xo` chokes on the top level aw…
gr2m Oct 2, 2021
12c5174
style: xo
gr2m Oct 3, 2021
d16bd93
remove `#readme` from `HOMEPAGE`
gr2m Oct 3, 2021
2c93202
ci: disable linting, remove `test:ci` script until we bring back linting
gr2m Oct 3, 2021
308530b
ci: disable `npx ls-engines` for now
gr2m Oct 3, 2021
e06fa6b
build(package): lock file
gr2m Nov 24, 2021
ba73adb
bump `quibble` to 0.6.6
gr2m Nov 24, 2021
bf717df
replace `xo` with just `prettier`
gr2m Nov 24, 2021
673017f
style: prettier
gr2m Nov 24, 2021
14e1a74
enable linting in test workflow
gr2m Nov 24, 2021
e100d3c
use `createRequire("../../package.json).homepage` instead of hardcodi…
gr2m Nov 24, 2021
0f12010
fix(deps): update dependency https-proxy-agent to v7 (#636)
renovate[bot] May 28, 2023
3c42e02
feat: add 'draftRelease' option (#379)
BetaHuhn May 28, 2023
c2135f1
Merge branch 'master' into 481/esm
gr2m May 28, 2023
9991f21
WIP temporarily use `node-fetch` as `nock` cannot intercept native fe…
gr2m May 28, 2023
521f663
fix merge errors from c2135f1
gr2m May 28, 2023
e6aa1c4
test only in Node 18+
gr2m May 28, 2023
467dfa0
remove quibble / need for mocking imports
gr2m May 28, 2023
4e462a8
replace nock with fetch-mock, run tests simultaneously
gr2m May 29, 2023
33342d9
remove node-fetch
gr2m May 29, 2023
365d9fb
fixup! replace nock with fetch-mock, run tests simultaneously
gr2m May 29, 2023
24dec8f
update dependencies
gr2m May 29, 2023
f4f1340
ci: add back `npx lockfile-lint --path package-lock.json`
gr2m May 29, 2023
decf761
remove default for `Octokit` in internal plugin functions
gr2m May 29, 2023
de0ef0b
add version to user agent in lib/octokit.js
gr2m May 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
/* eslint require-atomic-updates: off */

const {defaultTo, castArray} = require('lodash');
const verifyGitHub = require('./lib/verify');
const addChannelGitHub = require('./lib/add-channel');
const publishGitHub = require('./lib/publish');
const successGitHub = require('./lib/success');
const failGitHub = require('./lib/fail');
import {defaultTo, castArray} from 'lodash-es';

import verifyGitHub from './lib/verify.js';
import addChannelGitHub from './lib/add-channel.js';
import publishGitHub from './lib/publish.js';
import successGitHub from './lib/success.js';
import failGitHub from './lib/fail.js';

let verified;

async function verifyConditions(pluginConfig, context) {
export async function verifyConditions(pluginConfig, context) {
const {options} = context;
// If the GitHub publish plugin is used and has `assets`, `successComment`, `failComment`, `failTitle`, `labels` or `assignees` configured, validate it now in order to prevent any release if the configuration is wrong
if (options.publish) {
Expand All @@ -28,7 +29,7 @@ async function verifyConditions(pluginConfig, context) {
verified = true;
}

async function publish(pluginConfig, context) {
export async function publish(pluginConfig, context) {
if (!verified) {
await verifyGitHub(pluginConfig, context);
verified = true;
Expand All @@ -37,7 +38,7 @@ async function publish(pluginConfig, context) {
return publishGitHub(pluginConfig, context);
}

async function addChannel(pluginConfig, context) {
export async function addChannel(pluginConfig, context) {
if (!verified) {
await verifyGitHub(pluginConfig, context);
verified = true;
Expand All @@ -46,7 +47,7 @@ async function addChannel(pluginConfig, context) {
return addChannelGitHub(pluginConfig, context);
}

async function success(pluginConfig, context) {
export async function success(pluginConfig, context) {
if (!verified) {
await verifyGitHub(pluginConfig, context);
verified = true;
Expand All @@ -55,13 +56,11 @@ async function success(pluginConfig, context) {
await successGitHub(pluginConfig, context);
}

async function fail(pluginConfig, context) {
export async function fail(pluginConfig, context) {
if (!verified) {
await verifyGitHub(pluginConfig, context);
verified = true;
}

await failGitHub(pluginConfig, context);
}

module.exports = {verifyConditions, addChannel, publish, success, fail};
21 changes: 12 additions & 9 deletions lib/add-channel.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
const debug = require('debug')('semantic-release:github');
const {RELEASE_NAME} = require('./definitions/constants');
const parseGithubUrl = require('./parse-github-url');
const resolveConfig = require('./resolve-config');
const getClient = require('./get-client');
const isPrerelease = require('./is-prerelease');

module.exports = async (pluginConfig, context) => {
import debugFactory from 'debug';

import {RELEASE_NAME} from './definitions/constants.js';
import parseGithubUrl from './parse-github-url.js';
import resolveConfig from './resolve-config.js';
import getClient from './get-client.js';
import isPrerelease from './is-prerelease.js';

const debug = debugFactory('semantic-release:github');

export default async function addChannel(pluginConfig, context) {
const {
options: {repositoryUrl},
branch,
Expand Down Expand Up @@ -49,4 +52,4 @@ module.exports = async (pluginConfig, context) => {
logger.log('Updated GitHub release: %s', url);

return {url, name: RELEASE_NAME};
};
}
6 changes: 2 additions & 4 deletions lib/definitions/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const ISSUE_ID = '<!-- semantic-release:github -->';
export const ISSUE_ID = '<!-- semantic-release:github -->';

const RELEASE_NAME = 'GitHub release';

module.exports = {ISSUE_ID, RELEASE_NAME};
export const RELEASE_NAME = 'GitHub release';
112 changes: 76 additions & 36 deletions lib/definitions/errors.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,115 @@
const {inspect} = require('util');
const {isString} = require('lodash');
const pkg = require('../../package.json');
import {inspect} from 'node:util';

import {isString} from 'lodash-es';

const HOMEPAGE = 'https://github.com/semantic-release/github#readme';
gr2m marked this conversation as resolved.
Show resolved Hide resolved

const [homepage] = pkg.homepage.split('#');
const stringify = (object) =>
isString(object) ? object : inspect(object, {breakLength: Infinity, depth: 2, maxArrayLength: 5});
const linkify = (file) => `${homepage}/blob/master/${file}`;
isString(object) ? object : inspect(object, {breakLength: Number.POSITIVE_INFINITY, depth: 2, maxArrayLength: 5});
const linkify = (file) => `${HOMEPAGE}/blob/master/${file}`;

module.exports = {
EINVALIDASSETS: ({assets}) => ({
export function EINVALIDASSETS({assets}) {
return {
message: 'Invalid `assets` option.',
details: `The [assets option](${linkify(
'README.md#assets'
)}) must be an \`Array\` of \`Strings\` or \`Objects\` with a \`path\` property.

Your configuration for the \`assets\` option is \`${stringify(assets)}\`.`,
}),
EINVALIDSUCCESSCOMMENT: ({successComment}) => ({
};
}

export function EINVALIDSUCCESSCOMMENT({successComment}) {
return {
message: 'Invalid `successComment` option.',
details: `The [successComment option](${linkify(
'README.md#successcomment'
)}) if defined, must be a non empty \`String\`.

Your configuration for the \`successComment\` option is \`${stringify(successComment)}\`.`,
}),
EINVALIDFAILTITLE: ({failTitle}) => ({
};
}

export function EINVALIDFAILTITLE({failTitle}) {
return {
message: 'Invalid `failTitle` option.',
details: `The [failTitle option](${linkify('README.md#failtitle')}) if defined, must be a non empty \`String\`.

Your configuration for the \`failTitle\` option is \`${stringify(failTitle)}\`.`,
}),
EINVALIDFAILCOMMENT: ({failComment}) => ({
};
}

export function EINVALIDFAILCOMMENT({failComment}) {
return {
message: 'Invalid `failComment` option.',
details: `The [failComment option](${linkify('README.md#failcomment')}) if defined, must be a non empty \`String\`.

Your configuration for the \`failComment\` option is \`${stringify(failComment)}\`.`,
}),
EINVALIDLABELS: ({labels}) => ({
};
}

export function EINVALIDLABELS({labels}) {
return {
message: 'Invalid `labels` option.',
details: `The [labels option](${linkify(
'README.md#options'
)}) if defined, must be an \`Array\` of non empty \`String\`.

Your configuration for the \`labels\` option is \`${stringify(labels)}\`.`,
}),
EINVALIDASSIGNEES: ({assignees}) => ({
};
}

export function EINVALIDASSIGNEES({assignees}) {
return {
message: 'Invalid `assignees` option.',
details: `The [assignees option](${linkify('README.md#options')}) must be an \`Array\` of non empty \`Strings\`.

Your configuration for the \`assignees\` option is \`${stringify(assignees)}\`.`,
}),
EINVALIDRELEASEDLABELS: ({releasedLabels}) => ({
};
}

export function EINVALIDRELEASEDLABELS({releasedLabels}) {
return {
message: 'Invalid `releasedLabels` option.',
details: `The [releasedLabels option](${linkify(
'README.md#options'
)}) if defined, must be an \`Array\` of non empty \`String\`.

Your configuration for the \`releasedLabels\` option is \`${stringify(releasedLabels)}\`.`,
}),
EINVALIDADDRELEASES: ({addReleases}) => ({
};
}

export function EINVALIDADDRELEASES({addReleases}) {
return {
message: 'Invalid `addReleases` option.',
details: `The [addReleases option](${linkify('README.md#options')}) if defined, must be one of \`false|top|bottom\`.

Your configuration for the \`addReleases\` option is \`${stringify(addReleases)}\`.`,
}),
EINVALIDGITHUBURL: () => ({
};
}

export function EINVALIDGITHUBURL() {
return {
message: 'The git repository URL is not a valid GitHub URL.',
details: `The **semantic-release** \`repositoryUrl\` option must a valid GitHub URL with the format \`<GitHub_or_GHE_URL>/<owner>/<repo>.git\`.

By default the \`repositoryUrl\` option is retrieved from the \`repository\` property of your \`package.json\` or the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) of the repository cloned by your CI environment.`,
}),
EINVALIDPROXY: ({proxy}) => ({
};
}

export function EINVALIDPROXY({proxy}) {
return {
message: 'Invalid `proxy` option.',
details: `The [proxy option](${linkify(
'README.md#proxy'
)}) must be a \`String\` or an \`Objects\` with a \`host\` and a \`port\` property.

Your configuration for the \`proxy\` option is \`${stringify(proxy)}\`.`,
}),
EMISSINGREPO: ({owner, repo}) => ({
};
}

export function EMISSINGREPO({owner, repo}) {
return {
message: `The repository ${owner}/${repo} doesn't exist.`,
details: `The **semantic-release** \`repositoryUrl\` option must refer to your GitHub repository. The repository must be accessible with the [GitHub API](https://developer.github.com/v3).

Expand All @@ -87,29 +118,38 @@ By default the \`repositoryUrl\` option is retrieved from the \`repository\` pro
If you are using [GitHub Enterprise](https://enterprise.github.com) please make sure to configure the \`githubUrl\` and \`githubApiPathPrefix\` [options](${linkify(
'README.md#options'
)}).`,
}),
EGHNOPERMISSION: ({owner, repo}) => ({
};
}

export function EGHNOPERMISSION({owner, repo}) {
return {
message: `The GitHub token doesn't allow to push on the repository ${owner}/${repo}.`,
details: `The user associated with the [GitHub token](${linkify(
'README.md#github-authentication'
)}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must allows to push to the repository ${owner}/${repo}.

Please make sure the GitHub user associated with the token is an [owner](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#owner-access-on-a-repository-owned-by-a-user-account) or a [collaborator](https://help.github.com/articles/permission-levels-for-a-user-account-repository/#collaborator-access-on-a-repository-owned-by-a-user-account) if the reposotory belong to a user account or has [write permissions](https://help.github.com/articles/managing-team-access-to-an-organization-repository) if the repository [belongs to an organization](https://help.github.com/articles/repository-permission-levels-for-an-organization).`,
}),
EINVALIDGHTOKEN: ({owner, repo}) => ({
};
}

export function EINVALIDGHTOKEN({owner, repo}) {
return {
message: 'Invalid GitHub token.',
details: `The [GitHub token](${linkify(
'README.md#github-authentication'
)}) configured in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable must be a valid [personal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) allowing to push to the repository ${owner}/${repo}.

Please make sure to set the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable in your CI with the exact value of the GitHub personal token.`,
}),
ENOGHTOKEN: ({owner, repo}) => ({
};
}

export function ENOGHTOKEN({owner, repo}) {
return {
message: 'No GitHub token specified.',
details: `A [GitHub personal token](${linkify(
'README.md#github-authentication'
)}) must be created and set in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable on your CI environment.

Please make sure to create a [GitHub personal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) and to set it in the \`GH_TOKEN\` or \`GITHUB_TOKEN\` environment variable on your CI environment. The token must allow to push to the repository ${owner}/${repo}.`,
}),
};
};
}
8 changes: 3 additions & 5 deletions lib/definitions/rate-limit.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/**
* Default exponential backoff configuration for retries.
*/
const RETRY_CONF = {retries: 3, factor: 2, minTimeout: 1000};
export const RETRY_CONF = {retries: 3, factor: 2, minTimeout: 1000};

/**
* Rate limit per API endpoints.
*
* See {@link https://developer.github.com/v3/search/#rate-limit|Search API rate limit}.
* See {@link https://developer.github.com/v3/#rate-limiting|Rate limiting}.
*/
const RATE_LIMITS = {
export const RATE_LIMITS = {
search: ((60 * 1000) / 30) * 1.1, // 30 calls per minutes => 1 call every 2s + 10% safety margin
core: {
read: ((60 * 60 * 1000) / 5000) * 1.1, // 5000 calls per hour => 1 call per 720ms + 10% safety margin
Expand All @@ -22,6 +22,4 @@ const RATE_LIMITS = {
*
* See {@link https://developer.github.com/v3/guides/best-practices-for-integrators/#dealing-with-abuse-rate-limits|Dealing with abuse rate limits}
*/
const GLOBAL_RATE_LIMIT = 1000;

module.exports = {RETRY_CONF, RATE_LIMITS, GLOBAL_RATE_LIMIT};
export const GLOBAL_RATE_LIMIT = 1000;
32 changes: 21 additions & 11 deletions lib/fail.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const {template} = require('lodash');
const debug = require('debug')('semantic-release:github');
const parseGithubUrl = require('./parse-github-url');
const {ISSUE_ID} = require('./definitions/constants');
const resolveConfig = require('./resolve-config');
const getClient = require('./get-client');
const findSRIssues = require('./find-sr-issues');
const getFailComment = require('./get-fail-comment');
import {template} from 'lodash-es';
import debugFactory from 'debug';

module.exports = async (pluginConfig, context) => {
import parseGithubUrl from './parse-github-url.js';
import {ISSUE_ID} from './definitions/constants.js';
import resolveConfig from './resolve-config.js';
import getClient from './get-client.js';
import findSRIssues from './find-sr-issues.js';
import getFailComment from './get-fail-comment.js';

const debug = debugFactory('semantic-release:github');

export default async function fail(pluginConfig, context) {
const {
options: {repositoryUrl},
branch,
Expand Down Expand Up @@ -37,12 +40,19 @@ module.exports = async (pluginConfig, context) => {
} = await github.issues.createComment(comment);
logger.log('Added comment to issue #%d: %s.', srIssue.number, url);
} else {
const newIssue = {owner, repo, title: failTitle, body: `${body}\n\n${ISSUE_ID}`, labels: labels || [], assignees};
const newIssue = {
owner,
repo,
title: failTitle,
body: `${body}\n\n${ISSUE_ID}`,
labels: labels || [],
assignees,
};
debug('create issue: %O', newIssue);
const {
data: {html_url: url, number},
} = await github.issues.create(newIssue);
logger.log('Created issue #%d: %s.', number, url);
}
}
};
}
6 changes: 3 additions & 3 deletions lib/find-sr-issues.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const {ISSUE_ID} = require('./definitions/constants');
import {ISSUE_ID} from './definitions/constants.js';

module.exports = async (github, title, owner, repo) => {
export default async function findIssues(github, title, owner, repo) {
const {
data: {items: issues},
} = await github.search.issuesAndPullRequests({
q: `in:title+repo:${owner}/${repo}+type:issue+state:open+${title}`,
});

return issues.filter((issue) => issue.body && issue.body.includes(ISSUE_ID));
};
}
Loading