From 76eed6651264a2922770eef1dd71285b920ca6e8 Mon Sep 17 00:00:00 2001 From: Jonas Schubert Date: Fri, 11 Apr 2025 10:11:25 +0200 Subject: [PATCH] refactor(api): use ky and undici instead of got #756 --- README.md | 2 +- lib/fail.js | 12 +- lib/publish.js | 19 ++- lib/resolve-config.js | 103 -------------- lib/success.js | 32 ++--- lib/verify.js | 13 +- package-lock.json | 260 ++++------------------------------- package.json | 4 +- test/publish.test.js | 5 +- test/resolve-config.test.js | 262 +----------------------------------- test/verify.test.js | 2 +- 11 files changed, 72 insertions(+), 642 deletions(-) diff --git a/README.md b/README.md index 52c34296..89369a9e 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Create a [project access token](https://docs.gitlab.com/ee/user/project/settings #### Proxy configuration -The plugin supports passing requests through a proxy server. +The plugin supports passing requests through a proxy server using `undici`'s `EnvHttpProxyAgent`. You can configure a proxy server via the `HTTPS_PROXY` environment variable: `HTTPS_PROXY=http://proxyurl.com:8080` diff --git a/lib/fail.js b/lib/fail.js index 05516313..79a61ffc 100644 --- a/lib/fail.js +++ b/lib/fail.js @@ -1,6 +1,7 @@ +import { EnvHttpProxyAgent } from "undici"; import { template } from "lodash-es"; import urlJoin from "url-join"; -import got from "got"; +import ky from "ky"; import _debug from "debug"; const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; @@ -31,6 +32,7 @@ export default async (pluginConfig, context) => { headers: { "PRIVATE-TOKEN": gitlabToken }, retry: { limit: retryLimit }, }; + const kyInstance = ky.create(apiOptions).extend({ dispatcher: new EnvHttpProxyAgent() }); if (failComment === false || failTitle === false) { logger.log("Skip issue creation."); @@ -45,7 +47,7 @@ Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed const issuesEndpoint = urlJoin(projectApiUrl, `issues`); const openFailTitleIssueEndpoint = urlJoin(issuesEndpoint, `?state=opened&search=${encodedFailTitle}`); - const openFailTitleIssues = await got(openFailTitleIssueEndpoint, { ...apiOptions }).json(); + const openFailTitleIssues = await kyInstance.get(openFailTitleIssueEndpoint).json(); const existingIssue = openFailTitleIssues.find((openFailTitleIssue) => openFailTitleIssue.title === failTitle); const canCommentOnOrCreateIssue = failCommentCondition @@ -59,8 +61,7 @@ Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed gitlabApiUrl, `/projects/${existingIssue.project_id}/issues/${existingIssue.iid}/notes` ); - await got.post(issueNotesEndpoint, { - ...apiOptions, + await kyInstance.post(issueNotesEndpoint, { json: { body: description }, }); @@ -71,9 +72,8 @@ Using 'false' for 'failComment' or 'failTitle' is deprecated and will be removed debug("create issue: %O", newIssue); /* eslint camelcase: off */ - const { id, web_url } = await got + const { id, web_url } = await kyInstance .post(issuesEndpoint, { - ...apiOptions, json: newIssue, }) .json(); diff --git a/lib/publish.js b/lib/publish.js index 3f92f7e4..14347744 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -1,3 +1,4 @@ +import { EnvHttpProxyAgent } from "undici"; import { readFileSync } from "fs"; import pathlib from "path"; import fs from "fs-extra"; @@ -5,7 +6,7 @@ import { isPlainObject, template } from "lodash-es"; import { FormData } from "formdata-node"; import { fileFromPath } from "formdata-node/file-from-path"; import urlJoin from "url-join"; -import got from "got"; +import ky from "ky"; import _debug from "debug"; const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; @@ -22,10 +23,7 @@ export default async (pluginConfig, context) => { nextRelease: { gitTag, gitHead, notes, version }, logger, } = context; - const { gitlabToken, gitlabUrl, gitlabApiUrl, assets, milestones, proxy, retryLimit } = resolveConfig( - pluginConfig, - context - ); + const { gitlabToken, gitlabUrl, gitlabApiUrl, assets, milestones, retryLimit } = resolveConfig(pluginConfig, context); const assetsList = []; const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); @@ -42,7 +40,7 @@ export default async (pluginConfig, context) => { if (response?.body && response.headers["content-type"] === "application/json") { const parsedBody = JSON.parse(response.body); if (parsedBody.message) { - error.message = `Response code ${response.statusCode} (${parsedBody.message})`; + error.message = `Response code ${response.status} (${parsedBody.message})`; } } return error; @@ -51,6 +49,7 @@ export default async (pluginConfig, context) => { }, retry: { limit: retryLimit }, }; + const kyInstance = ky.create(apiOptions).extend({ dispatcher: new EnvHttpProxyAgent() }); debug("projectPath: %o", projectPath); debug("release name: %o", gitTag); @@ -123,7 +122,7 @@ export default async (pluginConfig, context) => { debug("PUT-ing the file %s to %s", file, uploadEndpoint); try { - response = await got.put(uploadEndpoint, { ...apiOptions, ...proxy, body: readFileSync(file) }).json(); + response = await kyInstance.put(uploadEndpoint, { body: readFileSync(file) }).json(); } catch (error) { logger.error("An error occurred while uploading %s to the GitLab generics package API:\n%O", file, error); throw error; @@ -144,7 +143,7 @@ export default async (pluginConfig, context) => { try { const form = new FormData(); form.append("file", await fileFromPath(file)); - response = await got.post(uploadEndpoint, { ...apiOptions, ...proxy, body: form }).json(); + response = await kyInstance.post(uploadEndpoint, { body: form }).json(); } catch (error) { logger.error("An error occurred while uploading %s to the GitLab project uploads API:\n%O", file, error); throw error; @@ -187,9 +186,7 @@ export default async (pluginConfig, context) => { debug("POST-ing the following JSON to %s:\n%s", createReleaseEndpoint, JSON.stringify(json, null, 2)); try { - await got.post(createReleaseEndpoint, { - ...apiOptions, - ...proxy, + await kyInstance.post(createReleaseEndpoint, { json, }); } catch (error) { diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 671fcd11..b8803b77 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -1,6 +1,5 @@ import { castArray, isNil } from "lodash-es"; import urlJoin from "url-join"; -import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; export default ( { @@ -29,9 +28,6 @@ export default ( GITLAB_URL, GL_PREFIX, GITLAB_PREFIX, - HTTP_PROXY, - HTTPS_PROXY, - NO_PROXY, }, } ) => { @@ -60,7 +56,6 @@ export default ( milestones: milestones ? castArray(milestones) : milestones, successComment, successCommentCondition, - proxy: getProxyConfiguration(defaultedGitlabUrl, HTTP_PROXY, HTTPS_PROXY, NO_PROXY), failTitle: isNil(failTitle) ? "The automated release is failing 🚨" : failTitle, failComment, failCommentCondition, @@ -69,101 +64,3 @@ export default ( retryLimit: retryLimit ?? DEFAULT_RETRY_LIMIT, }; }; - -// Copied from Rob Wu's great proxy-from-env library: https://github.com/Rob--W/proxy-from-env/blob/96d01f8fcfdccfb776735751132930bbf79c4a3a/index.js#L62 -function shouldProxy(gitlabUrl, NO_PROXY) { - const DEFAULT_PORTS = { - ftp: 21, - gopher: 70, - http: 80, - https: 443, - ws: 80, - wss: 443, - }; - const parsedUrl = - typeof gitlabUrl === "string" && (gitlabUrl.startsWith("http://") || gitlabUrl.startsWith("https://")) - ? new URL(gitlabUrl) - : gitlabUrl || {}; - let proto = parsedUrl.protocol; - let hostname = parsedUrl.host; - let { port } = parsedUrl; - if (typeof hostname !== "string" || !hostname || typeof proto !== "string") { - return ""; // Don't proxy URLs without a valid scheme or host. - } - - proto = proto.split(":", 1)[0]; - // Stripping ports in this way instead of using parsedUrl.hostname to make - // sure that the brackets around IPv6 addresses are kept. - hostname = hostname.replace(/:\d*$/, ""); - port = Number.parseInt(port, 10) || DEFAULT_PORTS[proto] || 0; - - if (!NO_PROXY) { - return true; // Always proxy if NO_PROXY is not set. - } - - if (NO_PROXY === "*") { - return false; // Never proxy if wildcard is set. - } - - return NO_PROXY.split(/[,\s]/).every((proxy) => { - if (!proxy) { - return true; // Skip zero-length hosts. - } - - const parsedProxy = proxy.match(/^(.+):(\d+)$/); - let parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy; - const parsedProxyPort = parsedProxy ? Number.parseInt(parsedProxy[2], 10) : 0; - if (parsedProxyPort && parsedProxyPort !== port) { - return true; // Skip if ports don't match. - } - - if (!/^[.*]/.test(parsedProxyHostname)) { - // No wildcards, so stop proxying if there is an exact match. - return hostname !== parsedProxyHostname; - } - - if (parsedProxyHostname.charAt(0) === "*") { - // Remove leading wildcard. - parsedProxyHostname = parsedProxyHostname.slice(1); - } - - // Stop proxying if the hostname ends with the no_proxy host. - return !hostname.endsWith(parsedProxyHostname); - }); -} - -function getProxyConfiguration(gitlabUrl, HTTP_PROXY, HTTPS_PROXY, NO_PROXY) { - const sharedParameters = { - keepAlive: true, - keepAliveMsecs: 1000, - maxSockets: 256, - maxFreeSockets: 256, - scheduling: "lifo", - }; - - if (shouldProxy(gitlabUrl, NO_PROXY)) { - if (HTTP_PROXY && gitlabUrl.startsWith("http://")) { - return { - agent: { - http: new HttpProxyAgent({ - ...sharedParameters, - proxy: HTTP_PROXY, - }), - }, - }; - } - - if (HTTPS_PROXY && gitlabUrl.startsWith("https://")) { - return { - agent: { - https: new HttpsProxyAgent({ - ...sharedParameters, - proxy: HTTPS_PROXY, - }), - }, - }; - } - } - - return {}; -} diff --git a/lib/success.js b/lib/success.js index 929b6b9e..ce58f988 100644 --- a/lib/success.js +++ b/lib/success.js @@ -1,6 +1,7 @@ +import { EnvHttpProxyAgent } from "undici"; import { uniqWith, isEqual, template } from "lodash-es"; import urlJoin from "url-join"; -import got from "got"; +import ky from "ky"; import _debug from "debug"; const debug = _debug("semantic-release:gitlab"); import resolveConfig from "./resolve-config.js"; @@ -15,13 +16,16 @@ export default async (pluginConfig, context) => { commits, releases, } = context; - const { gitlabToken, gitlabUrl, gitlabApiUrl, successComment, successCommentCondition, proxy, retryLimit } = - resolveConfig(pluginConfig, context); + const { gitlabToken, gitlabUrl, gitlabApiUrl, successComment, successCommentCondition, retryLimit } = resolveConfig( + pluginConfig, + context + ); const { projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); const apiOptions = { headers: { "PRIVATE-TOKEN": gitlabToken }, retry: { limit: retryLimit }, }; + const kyInstance = ky.create(apiOptions).extend({ dispatcher: new EnvHttpProxyAgent() }); if (successComment === false) { logger.log("Skip commenting on issues and pull requests."); @@ -42,9 +46,7 @@ Using 'false' for 'successComment' is deprecated and will be removed in a future const body = successComment ? template(successComment)({ ...context, issue, mergeRequest: false }) : getSuccessComment(issue, releaseInfos, nextRelease); - return got.post(issueNotesEndpoint, { - ...apiOptions, - ...proxy, + return kyInstance.post(issueNotesEndpoint, { json: { body }, }); } else { @@ -65,9 +67,7 @@ Using 'false' for 'successComment' is deprecated and will be removed in a future const body = successComment ? template(successComment)({ ...context, issue: false, mergeRequest }) : getSuccessComment({ isMergeRequest: true, ...mergeRequest }, releaseInfos, nextRelease); - return got.post(mergeRequestNotesEndpoint, { - ...apiOptions, - ...proxy, + return kyInstance.post(mergeRequestNotesEndpoint, { json: { body }, }); } else { @@ -78,12 +78,7 @@ Using 'false' for 'successComment' is deprecated and will be removed in a future const getRelatedMergeRequests = async (commitHash) => { const relatedMergeRequestsEndpoint = urlJoin(projectApiUrl, `repository/commits/${commitHash}/merge_requests`); debug("Getting MRs from %s", relatedMergeRequestsEndpoint); - const relatedMergeRequests = await got - .get(relatedMergeRequestsEndpoint, { - ...apiOptions, - ...proxy, - }) - .json(); + const relatedMergeRequests = await kyInstance.get(relatedMergeRequestsEndpoint).json(); return relatedMergeRequests.filter((x) => x.state === "merged"); }; @@ -94,12 +89,7 @@ Using 'false' for 'successComment' is deprecated and will be removed in a future `/projects/${mergeRequest.project_id}/merge_requests/${mergeRequest.iid}/closes_issues` ); debug("Getting related issues from %s", relatedIssuesEndpoint); - const relatedIssues = await got - .get(relatedIssuesEndpoint, { - ...apiOptions, - ...proxy, - }) - .json(); + const relatedIssues = await kyInstance.get(relatedIssuesEndpoint).json(); return relatedIssues.filter((x) => x.state === "closed"); }; diff --git a/lib/verify.js b/lib/verify.js index fdfc3b7f..12c93d20 100644 --- a/lib/verify.js +++ b/lib/verify.js @@ -1,5 +1,6 @@ +import { EnvHttpProxyAgent } from "undici"; import { isString, isPlainObject, isNil, isArray } from "lodash-es"; -import got from "got"; +import ky from "ky"; import _debug from "debug"; const debug = _debug("semantic-release:gitlab"); import AggregateError from "aggregate-error"; @@ -30,7 +31,7 @@ export default async (pluginConfig, context) => { options: { repositoryUrl }, logger, } = context; - const { gitlabToken, gitlabUrl, gitlabApiUrl, proxy, ...options } = resolveConfig(pluginConfig, context); + const { gitlabToken, gitlabUrl, gitlabApiUrl, ...options } = resolveConfig(pluginConfig, context); const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); debug("apiUrl: %o", gitlabApiUrl); @@ -62,10 +63,10 @@ export default async (pluginConfig, context) => { try { ({ permissions: { project_access: projectAccess, group_access: groupAccess }, - } = await got + } = await ky + .extend({ dispatcher: new EnvHttpProxyAgent() }) .get(projectApiUrl, { headers: { "PRIVATE-TOKEN": gitlabToken }, - ...proxy, }) .json()); if ( @@ -79,9 +80,9 @@ export default async (pluginConfig, context) => { errors.push(getError("EGLNOPUSHPERMISSION", { projectPath })); } } catch (error) { - if (error.response && error.response.statusCode === 401) { + if (error.response && error.response.status === 401) { errors.push(getError("EINVALIDGLTOKEN", { projectPath })); - } else if (error.response && error.response.statusCode === 404) { + } else if (error.response && error.response.status === 404) { errors.push(getError("EMISSINGREPO", { projectPath })); } else { throw error; diff --git a/package-lock.json b/package-lock.json index 7a9b97f3..cf61a49f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,10 +17,10 @@ "formdata-node": "^6.0.3", "fs-extra": "^11.0.0", "globby": "^14.0.0", - "got": "^14.0.0", - "hpagent": "^1.0.0", + "ky": "^1.8.0", "lodash-es": "^4.17.21", "parse-url": "^9.0.0", + "undici": "^7.7.0", "url-join": "^4.0.0" }, "devDependencies": { @@ -666,6 +666,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, "license": "MIT" }, "node_modules/@semantic-release/commit-analyzer": { @@ -897,18 +898,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sindresorhus/is": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.1.tgz", - "integrity": "sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -963,18 +952,6 @@ "node": ">=4" } }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.1" - }, - "engines": { - "node": ">=14.16" - } - }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -982,12 +959,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "license": "MIT" - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -1392,33 +1363,6 @@ } } }, - "node_modules/cacheable-lookup": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", - "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", - "license": "MIT", - "engines": { - "node": ">=14.16" - } - }, - "node_modules/cacheable-request": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-12.0.1.tgz", - "integrity": "sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==", - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "^4.0.4", - "get-stream": "^9.0.1", - "http-cache-semantics": "^4.1.1", - "keyv": "^4.5.4", - "mimic-response": "^4.0.0", - "normalize-url": "^8.0.1", - "responselike": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -2190,33 +2134,6 @@ "dev": true, "license": "MIT" }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2227,15 +2144,6 @@ "node": ">=4.0.0" } }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/del": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", @@ -2949,15 +2857,6 @@ "node": ">= 6" } }, - "node_modules/form-data-encoder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz", - "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, "node_modules/formdata-node": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-6.0.3.tgz", @@ -3088,6 +2987,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, "license": "MIT", "dependencies": { "@sec-ant/readable-stream": "^0.4.1", @@ -3194,31 +3094,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "14.4.6", - "resolved": "https://registry.npmjs.org/got/-/got-14.4.6.tgz", - "integrity": "sha512-rnhwfM/PhMNJ1i17k3DuDqgj0cKx3IHxBKVv/WX1uDKqrhi2Gv3l7rhPThR/Cc6uU++dD97W9c8Y0qyw9x0jag==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^7.0.1", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^7.0.0", - "cacheable-request": "^12.0.1", - "decompress-response": "^6.0.0", - "form-data-encoder": "^4.0.2", - "http2-wrapper": "^2.2.1", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^4.0.1", - "responselike": "^3.0.0", - "type-fest": "^4.26.1" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3335,15 +3210,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/hpagent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", - "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -3364,12 +3230,6 @@ "dev": true, "license": "MIT" }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "license": "BSD-2-Clause" - }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -3384,19 +3244,6 @@ "node": ">= 14" } }, - "node_modules/http2-wrapper": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", - "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -3721,6 +3568,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3909,12 +3757,6 @@ } } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "license": "MIT" - }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -3948,13 +3790,16 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/ky": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.8.0.tgz", + "integrity": "sha512-DoKGmG27nT8t/1F9gV8vNzggJ3mLAyD49J8tTMWHeZvS8qLc7GlyTieicYtFzvDznMe/q2u38peOjkWc5/pjvw==", "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" } }, "node_modules/lines-and-columns": { @@ -4049,18 +3894,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -4293,18 +4126,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4560,6 +4381,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.16" @@ -7409,15 +7231,6 @@ "dev": true, "license": "MIT" }, - "node_modules/p-cancelable": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", - "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", - "license": "MIT", - "engines": { - "node": ">=14.16" - } - }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -7957,18 +7770,6 @@ ], "license": "MIT" }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -8093,12 +7894,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "license": "MIT" - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -8122,21 +7917,6 @@ "node": ">=8" } }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "license": "MIT", - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -9250,6 +9030,7 @@ "version": "4.38.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz", "integrity": "sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -9272,6 +9053,15 @@ "node": ">=0.8.0" } }, + "node_modules/undici": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.7.0.tgz", + "integrity": "sha512-tZ6+5NBq4KH35rr46XJ2JPFKxfcBlYNaqLF/wyWIO9RMHqqU/gx/CLB1Y2qMcgB8lWw/bKHa7qzspqCN7mUHvA==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/unicode-emoji-modifier-base": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", diff --git a/package.json b/package.json index de9da452..7ad26a4d 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,10 @@ "formdata-node": "^6.0.3", "fs-extra": "^11.0.0", "globby": "^14.0.0", - "got": "^14.0.0", - "hpagent": "^1.0.0", + "ky": "^1.8.0", "lodash-es": "^4.17.21", "parse-url": "^9.0.0", + "undici": "^7.7.0", "url-join": "^4.0.0" }, "devDependencies": { diff --git a/test/publish.test.js b/test/publish.test.js index 249e8bcf..48672502 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -663,6 +663,9 @@ test.serial("Publish a release with error response", async (t) => { .reply(499, { message: "Something went wrong" }); const error = await t.throwsAsync(publish(pluginConfig, { env, options, nextRelease, logger: t.context.logger })); - t.is(error.message, `Response code 499 (Something went wrong)`); + t.is( + error.message, + "Request failed with status code 499: POST https://gitlab.com/api/v4/projects/test_user%2Ftest_repo/releases" + ); t.true(gitlab.isDone()); }); diff --git a/test/resolve-config.test.js b/test/resolve-config.test.js index 525e9e48..9fb8dc61 100644 --- a/test/resolve-config.test.js +++ b/test/resolve-config.test.js @@ -1,6 +1,5 @@ import test from "ava"; import urlJoin from "url-join"; -import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"; import resolveConfig from "../lib/resolve-config.js"; const defaultOptions = { @@ -16,7 +15,6 @@ const defaultOptions = { failCommentCondition: undefined, labels: "semantic-release", assignee: undefined, - proxy: {}, retryLimit: 3, }; @@ -26,7 +24,6 @@ test("Returns user config", (t) => { const gitlabApiPathPrefix = "/api/prefix"; const assets = ["file.js"]; const postComments = true; - const proxy = {}; const labels = false; const retryLimit = 42; @@ -46,17 +43,13 @@ test("Returns user config", (t) => { } ); - t.deepEqual( - resolveConfig({ gitlabUrl, gitlabApiPathPrefix, assets, proxy }, { env: { GITLAB_TOKEN: gitlabToken } }), - { - ...defaultOptions, - gitlabToken, - gitlabUrl, - gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), - assets, - proxy, - } - ); + t.deepEqual(resolveConfig({ gitlabUrl, gitlabApiPathPrefix, assets }, { env: { GITLAB_TOKEN: gitlabToken } }), { + ...defaultOptions, + gitlabToken, + gitlabUrl, + gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix), + assets, + }); }); test("Returns user config via environment variables", (t) => { @@ -102,247 +95,6 @@ test("Returns user config via alternative environment variables", (t) => { ); }); -test("Returns user config via alternative environment variables with https proxy and no proto scheme set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8443"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTPS_PROXY: proxyUrl, - }, - } - ); - - t.deepEqual(result.proxy, {}); -}); - -test("Returns user config via alternative environment variables with http proxy and no proto scheme set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8080"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTP_PROXY: proxyUrl, - }, - } - ); - - t.deepEqual(result.proxy, {}); -}); - -test("Returns user config via alternative environment variables with http proxy", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "http://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8080"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTP_PROXY: proxyUrl, - }, - } - ); - - t.assert(result.proxy.agent.http instanceof HttpProxyAgent); - t.assert(result.proxy.agent.http.proxy.origin === proxyUrl); -}); - -test("Returns user config via alternative environment variables with https proxy", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "https://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8443 port because HttpsProxyAgent ignores 443 port with https protocol - const proxyUrl = "http://proxy.test:8443"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTPS_PROXY: proxyUrl, - }, - } - ); - - t.assert(result.proxy.agent.https instanceof HttpsProxyAgent); - t.assert(result.proxy.agent.https.proxy.origin === proxyUrl); -}); - -test("Returns user config via alternative environment variables with mismatching http/https values for proxy gitlab url", (t) => { - const gitlabToken = "TOKEN"; - const httpGitlabUrl = "http://host.com"; - const gitlabUrl = "https://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8443 port because HttpsProxyAgent ignores 443 port with https protocol - - // HTTP GitLab URL and HTTPS_PROXY set - t.deepEqual( - resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: httpGitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTPS_PROXY: "https://proxy.test:8443", - }, - } - ), - { - ...defaultOptions, - gitlabToken: "TOKEN", - gitlabUrl: "http://host.com", - gitlabApiUrl: "http://host.com/api/prefix", - assets: ["file.js"], - } - ); - - // HTTPS GitLab URL and HTTP_PROXY set - t.deepEqual( - resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTP_PROXY: "http://proxy.test:8443", - }, - } - ), - { - ...defaultOptions, - gitlabToken: "TOKEN", - gitlabUrl: "https://host.com", - gitlabApiUrl: "https://host.com/api/prefix", - assets: ["file.js"], - } - ); -}); -test("Returns user config via environment variables with HTTP_PROXY and NO_PROXY set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "http://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8080"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTP_PROXY: proxyUrl, - NO_PROXY: "*.host.com, host.com", - }, - } - ); - - t.deepEqual(result.proxy, {}); -}); - -test("Returns user config via environment variables with HTTPS_PROXY and NO_PROXY set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "https://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8080"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTPS_PROXY: proxyUrl, - NO_PROXY: "*.host.com, host.com", - }, - } - ); - t.deepEqual(result.proxy, {}); -}); - -test("Returns user config via environment variables with HTTPS_PROXY and non-matching NO_PROXY set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "https://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8443 port because HttpsProxyAgent ignores 443 port with http protocol - const proxyUrl = "https://proxy.test:8443"; - process.env.HTTPS_PROXY = proxyUrl; - process.env.NO_PROXY = "*.differenthost.com, differenthost.com"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTPS_PROXY: proxyUrl, - NO_PROXY: "*.differenthost.com, differenthost.com", - }, - } - ); - t.assert(result.proxy.agent.https instanceof HttpsProxyAgent); -}); - -test("Returns user config via environment variables with HTTP_PROXY and non-matching NO_PROXY set", (t) => { - const gitlabToken = "TOKEN"; - const gitlabUrl = "http://host.com"; - const gitlabApiPathPrefix = "/api/prefix"; - const assets = ["file.js"]; - // Testing with 8080 port because HttpsProxyAgent ignores 80 port with http protocol - const proxyUrl = "http://proxy.test:8080"; - - const result = resolveConfig( - { assets }, - { - env: { - GL_TOKEN: gitlabToken, - GL_URL: gitlabUrl, - GL_PREFIX: gitlabApiPathPrefix, - HTTP_PROXY: proxyUrl, - NO_PROXY: "*.differenthost.com, differenthost.com", - }, - } - ); - t.assert(result.proxy.agent.http instanceof HttpProxyAgent); -}); - test("Returns default config", (t) => { const gitlabToken = "TOKEN"; const gitlabApiPathPrefix = "/api/prefix"; diff --git a/test/verify.test.js b/test/verify.test.js index 48f3004f..e5f6b88a 100644 --- a/test/verify.test.js +++ b/test/verify.test.js @@ -573,7 +573,7 @@ test.serial("Throw error if GitLab API return any other errors", async (t) => { verify({}, { env, options: { repositoryUrl: `https://gitlab.com:${owner}/${repo}.git` }, logger: t.context.logger }) ); - t.is(error.response.statusCode, 500); + t.is(error.response.status, 500); t.true(gitlab.isDone()); });