Skip to content

Commit

Permalink
Merge branch 'master' into 481/esm
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m committed May 28, 2023
2 parents e100d3c + 3c42e02 commit c2135f1
Show file tree
Hide file tree
Showing 28 changed files with 4,676 additions and 12,862 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ name: Release
- next
- beta
- "*.x"
permissions:
contents: read # for checkout
jobs:
release:
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
cache: npm
node-version: 16
node-version: lts/*
- run: npm ci
- run: npx semantic-release
env:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jobs:
- ubuntu-latest
runs-on: "${{ matrix.os }}"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- name: "Use Node.js ${{ matrix.node-version }}"
uses: actions/setup-node@v2
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: "${{ matrix.node-version }}"
cache: npm
Expand All @@ -31,8 +31,8 @@ jobs:
runs-on: ubuntu-latest
needs: test_matrix
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: 16
cache: npm
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ When creating the token, the **minimum required scopes** are:
_Note on GitHub Actions:_ You can use the default token which is provided in the secret _GITHUB_TOKEN_. However releases done with this token will NOT trigger release events to start other workflows.
If you have actions that trigger on newly created releases, please use a generated token for that and store it in your repository's secrets (any other name than GITHUB_TOKEN is fine).

When using the _GITHUB_TOKEN_, the **minimum required permissions** are:

- `contents: write` to be able to publish a GitHub release
- `issues: write` to be able to comment on released issues
- `pull-requests: write` to be able to comment on released pull requests

### Environment variables

| Variable | Description |
Expand All @@ -86,6 +92,7 @@ If you have actions that trigger on newly created releases, please use a generat
| `assignees` | The [assignees](https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users) to add to the issue created when a release fails. | - |
| `releasedLabels` | The [labels](https://help.github.com/articles/about-labels) to add to each issue and pull request resolved by the release. Set to `false` to not add any label. See [releasedLabels](#releasedlabels). | `['released<%= nextRelease.channel ? \` on @\${nextRelease.channel}\` : "" %>']- |
| `addReleases` | Will add release links to the GitHub Release. Can be `false`, `"bottom"` or `"top"`. See [addReleases](#addReleases). | `false` |
| `draftRelease` | A boolean indicating if a GitHub Draft Release should be created instead of publishing an actual GitHub Release. | `false` |

#### proxy

Expand Down
18 changes: 14 additions & 4 deletions lib/add-channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default async function addChannel(pluginConfig, context) {
context
);
const { owner, repo } = parseGithubUrl(repositoryUrl);
const github = getClient({
const octokit = getClient({
githubToken,
githubUrl,
githubApiPathPrefix,
Expand All @@ -41,14 +41,21 @@ export default async function addChannel(pluginConfig, context) {
try {
({
data: { id: releaseId },
} = await github.repos.getReleaseByTag({ owner, repo, tag: gitTag }));
} = await octokit.request("GET /repos/{owner}/{repo}/releases/tags/{tag}", {
owner,
repo,
tag: gitTag,
}));
} catch (error) {
if (error.status === 404) {
logger.log("There is no release for tag %s, creating a new one", gitTag);

const {
data: { html_url: url },
} = await github.repos.createRelease({ ...release, body: notes });
} = await octokit.request("POST /repos/{owner}/{repo}/releases", {
...release,
body: notes,
});

logger.log("Published GitHub release: %s", url);
return { url, name: RELEASE_NAME };
Expand All @@ -61,7 +68,10 @@ export default async function addChannel(pluginConfig, context) {

const {
data: { html_url: url },
} = await github.repos.updateRelease({ ...release, release_id: releaseId });
} = await octokit.request(
"PATCH /repos/{owner}/{repo}/releases/{release_id}",
{ ...release, release_id: releaseId }
);

logger.log("Updated GitHub release: %s", url);

Expand Down
13 changes: 13 additions & 0 deletions lib/definitions/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ Your configuration for the \`addReleases\` option is \`${stringify(
};
}

export function EINVALIDDRAFTRELEASE({ draftRelease }) {
return {
message: "Invalid `draftRelease` option.",
details: `The [draftRelease option](${linkify(
"README.md#options"
)}) if defined, must be a \`Boolean\`.
Your configuration for the \`draftRelease\` option is \`${stringify(
draftRelease
)}\`.`,
};
}

export function EINVALIDGITHUBURL() {
return {
message: "The git repository URL is not a valid GitHub URL.",
Expand Down
25 changes: 0 additions & 25 deletions lib/definitions/rate-limit.js

This file was deleted.

8 changes: 8 additions & 0 deletions lib/definitions/retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Default exponential backoff configuration for retries.
*/
export const RETRY_CONF = {
// By default, Octokit does not retry on 404s.
// But we want to retry on 404s to account for replication lag.
doNotRetry: [400, 401, 403, 422],
};
5 changes: 5 additions & 0 deletions lib/definitions/throttle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Default configuration for throttle.
* @see https://github.com/octokit/plugin-throttling.js#options
*/
export const THROTTLE_CONF = {};
19 changes: 12 additions & 7 deletions lib/fail.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,33 @@ export default async function fail(pluginConfig, context) {
if (failComment === false || failTitle === false) {
logger.log("Skip issue creation.");
} else {
const github = getClient({
const octokit = getClient({
githubToken,
githubUrl,
githubApiPathPrefix,
proxy,
});
// In case the repo changed name, get the new `repo`/`owner` as the search API will not follow redirects
const [owner, repo] = (
await github.repos.get(parseGithubUrl(repositoryUrl))
).data.full_name.split("/");
const { data: repoData } = await octokit.request(
"GET /repos/{owner}/{repo}",
parseGithubUrl(repositoryUrl)
);
const [owner, repo] = repoData.full_name.split("/");
const body = failComment
? template(failComment)({ branch, errors })
: getFailComment(branch, errors);
const [srIssue] = await findSRIssues(github, failTitle, owner, repo);
const [srIssue] = await findSRIssues(octokit, failTitle, owner, repo);

if (srIssue) {
logger.log("Found existing semantic-release issue #%d.", srIssue.number);
const comment = { owner, repo, issue_number: srIssue.number, body };
debug("create comment: %O", comment);
const {
data: { html_url: url },
} = await github.issues.createComment(comment);
} = await octokit.request(
"POST /repos/{owner}/{repo}/issues/{issue_number}/comments",
comment
);
logger.log("Added comment to issue #%d: %s.", srIssue.number, url);
} else {
const newIssue = {
Expand All @@ -66,7 +71,7 @@ export default async function fail(pluginConfig, context) {
debug("create issue: %O", newIssue);
const {
data: { html_url: url, number },
} = await github.issues.create(newIssue);
} = await octokit.request("POST /repos/{owner}/{repo}/issues", newIssue);
logger.log("Created issue #%d: %s.", number, url);
}
}
Expand Down
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 @@
import { ISSUE_ID } from "./definitions/constants.js";

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

return issues.filter((issue) => issue.body && issue.body.includes(ISSUE_ID));
}
};
65 changes: 9 additions & 56 deletions lib/get-client.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,8 @@
import { memoize, get } from "lodash-es";
import { Octokit } from "@octokit/rest";
import pRetry, { AbortError } from "p-retry";
import Bottleneck from "bottleneck";
import urljoin from "url-join";
import HttpProxyAgent from "http-proxy-agent";
import HttpsProxyAgent from "https-proxy-agent";
import { HttpProxyAgent } from "http-proxy-agent";
import { HttpsProxyAgent } from "https-proxy-agent";

import {
RETRY_CONF,
RATE_LIMITS,
GLOBAL_RATE_LIMIT,
} from "./definitions/rate-limit.js";

/**
* Http error status for which to not retry.
*/
const SKIP_RETRY_CODES = new Set([400, 401, 403]);

/**
* Create or retrieve the throttler function for a given rate limit group.
*
* @param {Array} rate The rate limit group.
* @param {String} limit The rate limits per API endpoints.
* @param {Bottleneck} globalThrottler The global throttler.
*
* @return {Bottleneck} The throller function for the given rate limit group.
*/
const getThrottler = memoize((rate, globalThrottler) =>
new Bottleneck({ minTime: get(RATE_LIMITS, rate) }).chain(globalThrottler)
);
import SemanticReleaseOctokit from "./semantic-release-octokit.js";

export default function getClient({
githubToken,
Expand All @@ -37,40 +11,19 @@ export default function getClient({
proxy,
}) {
const baseUrl = githubUrl && urljoin(githubUrl, githubApiPathPrefix);
const globalThrottler = new Bottleneck({ minTime: GLOBAL_RATE_LIMIT });
const github = new Octokit({
const octokit = new SemanticReleaseOctokit({
auth: `token ${githubToken}`,
baseUrl,
request: {
agent: proxy
? baseUrl && new URL(baseUrl).protocol.replace(":", "") === "http"
? new HttpProxyAgent(proxy)
: new HttpsProxyAgent(proxy)
? // Some `proxy.headers` need to be passed as second arguments since version 6 or 7
// For simplicity, we just pass the same proxy object twice. It works 🤷🏻
new HttpProxyAgent(proxy, proxy)
: new HttpsProxyAgent(proxy, proxy)
: undefined,
},
});

github.hook.wrap("request", (request, options) => {
const access = options.method === "GET" ? "read" : "write";
const rateCategory = options.url.startsWith("/search") ? "search" : "core";
const limitKey = [rateCategory, RATE_LIMITS[rateCategory][access] && access]
.filter(Boolean)
.join(".");

return pRetry(async () => {
try {
return await getThrottler(limitKey, globalThrottler).wrap(request)(
options
);
} catch (error) {
if (SKIP_RETRY_CODES.has(error.status)) {
throw new AbortError(error);
}

throw error;
}
}, RETRY_CONF);
});

return github;
return octokit;
}
Loading

0 comments on commit c2135f1

Please sign in to comment.