diff --git a/README.md b/README.md index 52c34296..de63dbac 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ If you need to bypass the proxy for some hosts, configure the `NO_PROXY` environ | `labels` | The [labels](https://docs.gitlab.com/ee/user/project/labels.html#labels) to add to the issue created when a release fails. Set to `false` to not add any label. Labels should be comma-separated as described in the [official docs](https://docs.gitlab.com/ee/api/issues.html#new-issue), e.g. `"semantic-release,bot"`. | `semantic-release` | | `assignee` | The [assignee](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#assignee) to add to the issue created when a release fails. | - | | `retryLimit` | The maximum number of retries for failing HTTP requests. | `3` | +| `publishToCatalog` | [EXPERIMENTAL] Publishes CI/CD components to the catalog. See [publishToCatalog](#publishToCatalog). | `false` | #### assets @@ -211,6 +212,14 @@ The fail comment condition is generated with [Lodash template](https://lodash.co > check the [GitLab API Issue object](https://docs.gitlab.com/ee/api/issues.html#single-issue) for properties which can be used for the filter +#### publishToCatalog + +**Note**: This is an EXPERIMENTAL option that might change in the future. + +Use this option to [publish CI/CD components to the catalog](https://gitlab.com/gitlab-org/cli/-/blob/main/docs/source/repo/publish/catalog.md) as part of the release process. + +The publishing is done via the `glab` CLI, so make sure to [install it before](https://gitlab.com/gitlab-org/cli#installation). + ## Compatibility The latest version of this plugin is compatible with all currently-supported versions of GitLab, [which is the current major version and previous two major versions](https://about.gitlab.com/support/statement-of-support.html#version-support). This plugin is not guaranteed to work with unsupported versions of GitLab. diff --git a/lib/publish.js b/lib/publish.js index 3f92f7e4..379cf68b 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -12,7 +12,7 @@ import resolveConfig from "./resolve-config.js"; import getAssets from "./glob-assets.js"; import { RELEASE_NAME } from "./definitions/constants.js"; import getProjectContext from "./get-project-context.js"; - +import { execa } from "execa"; const isUrlScheme = (value) => /^(https|http|ftp):\/\//.test(value); export default async (pluginConfig, context) => { @@ -22,19 +22,15 @@ 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, proxy, retryLimit, publishToCatalog } = + resolveConfig(pluginConfig, context); const assetsList = []; const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl); const encodedGitTag = encodeURIComponent(gitTag); const encodedVersion = encodeURIComponent(version); const apiOptions = { - headers: { - "PRIVATE-TOKEN": gitlabToken, - }, + headers: { "PRIVATE-TOKEN": gitlabToken }, hooks: { beforeError: [ (error) => { @@ -187,11 +183,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, - json, - }); + await got.post(createReleaseEndpoint, { ...apiOptions, ...proxy, json }); } catch (error) { logger.error("An error occurred while making a request to the GitLab release API:\n%O", error); throw error; @@ -201,5 +193,19 @@ export default async (pluginConfig, context) => { const releaseUrl = urlJoin(gitlabUrl, projectPath, `/-/releases/${encodedGitTag}`); + if (publishToCatalog) { + try { + await execa("glab", ["repo", "publish", "catalog", gitTag], { + cwd, + timeout: 30 * 1000, + env: { GITLAB_TOKEN: gitlabToken }, + }); + logger.log("Published tag %s to the CI catalog", gitTag); + } catch (error) { + logger.error("An error occurred while publishing tag %s to the CI catalog:\n%O", gitTag, error); + throw error; + } + } + return { name: RELEASE_NAME, url: releaseUrl }; }; diff --git a/lib/resolve-config.js b/lib/resolve-config.js index 671fcd11..92e92ba3 100644 --- a/lib/resolve-config.js +++ b/lib/resolve-config.js @@ -16,6 +16,7 @@ export default ( labels, assignee, retryLimit, + publishToCatalog, }, { envCi: { service } = {}, @@ -67,6 +68,7 @@ export default ( labels: isNil(labels) ? "semantic-release" : labels === false ? false : labels, assignee, retryLimit: retryLimit ?? DEFAULT_RETRY_LIMIT, + publishToCatalog: publishToCatalog ?? false, }; }; diff --git a/package-lock.json b/package-lock.json index 7a9b97f3..b75fbab1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "debug": "^4.0.0", "dir-glob": "^3.0.0", "escape-string-regexp": "^5.0.0", + "execa": "^9.5.2", "formdata-node": "^6.0.3", "fs-extra": "^11.0.0", "globby": "^14.0.0", @@ -30,7 +31,8 @@ "prettier": "3.5.3", "semantic-release": "24.2.3", "sinon": "20.0.0", - "tempy": "1.0.1" + "tempy": "1.0.1", + "testdouble": "^3.20.2" }, "engines": { "node": ">=20.8.1" @@ -2091,7 +2093,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -2749,7 +2750,6 @@ "version": "9.5.2", "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -2776,7 +2776,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -2838,7 +2837,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", - "dev": true, "license": "MIT", "dependencies": { "is-unicode-supported": "^2.0.0" @@ -3415,7 +3413,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -3600,6 +3597,22 @@ "dev": true, "license": "MIT" }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3684,7 +3697,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3717,6 +3729,16 @@ "dev": true, "license": "MIT" }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", @@ -3733,7 +3755,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3753,7 +3774,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/issue-parser": { @@ -4733,7 +4753,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^4.0.0", @@ -4750,7 +4769,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7595,7 +7613,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7680,12 +7697,18 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -7885,7 +7908,6 @@ "version": "9.2.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", - "dev": true, "license": "MIT", "dependencies": { "parse-ms": "^4.0.0" @@ -7957,6 +7979,20 @@ ], "license": "MIT" }, + "node_modules/quibble": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.9.2.tgz", + "integrity": "sha512-BrL7hrZcbyyt5ZDfePkGFDc3m82uUtxCPOnpRUrkOdtBnmV9ldQKxXORkKL8eIzToRNaCpIPyKyfdfq/tBlFAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">= 0.14.0" + } + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -8093,6 +8129,27 @@ "node": ">=0.10.0" } }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-alpn": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", @@ -8399,7 +8456,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -8412,7 +8468,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8422,7 +8477,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -8792,6 +8846,30 @@ "node": ">=8" } }, + "node_modules/stringify-object-es5": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz", + "integrity": "sha512-vE7Xdx9ylG4JI16zy7/ObKUB+MtxuMcWlj/WHHr3+yAlQoN6sst2stU9E+2Qs3OrlJw/Pf3loWxL1GauEHf6MA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "is-plain-obj": "^1.0.0", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stringify-object-es5/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -8846,7 +8924,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8952,6 +9029,19 @@ "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -9105,6 +9195,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/testdouble": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.20.2.tgz", + "integrity": "sha512-790e9vJKdfddWNOaxW1/V9FcMk48cPEl3eJSj2i8Hh1fX89qArEJ6cp3DBnaECpGXc3xKJVWbc1jeNlWYWgiMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "quibble": "^0.9.2", + "stringify-object-es5": "^2.5.0", + "theredoc": "^1.0.0" + }, + "engines": { + "node": ">= 16" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -9128,6 +9234,13 @@ "node": ">=0.8" } }, + "node_modules/theredoc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz", + "integrity": "sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA==", + "dev": true, + "license": "MIT" + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -9436,7 +9549,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9825,7 +9937,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" diff --git a/package.json b/package.json index de9da452..7265ec0e 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "debug": "^4.0.0", "dir-glob": "^3.0.0", "escape-string-regexp": "^5.0.0", + "execa": "^9.5.2", "formdata-node": "^6.0.3", "fs-extra": "^11.0.0", "globby": "^14.0.0", @@ -38,7 +39,8 @@ "prettier": "3.5.3", "semantic-release": "24.2.3", "sinon": "20.0.0", - "tempy": "1.0.1" + "tempy": "1.0.1", + "testdouble": "^3.20.2" }, "engines": { "node": ">=20.8.1" diff --git a/test/publish.test.js b/test/publish.test.js index 249e8bcf..97ef06fb 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -4,9 +4,9 @@ import tempy from "tempy"; import { stub } from "sinon"; import publish from "../lib/publish.js"; import authenticate from "./helpers/mock-gitlab.js"; +import * as td from "testdouble"; /* eslint camelcase: ["error", {properties: "never"}] */ - test.beforeEach((t) => { // Mock logger t.context.log = stub(); @@ -15,8 +15,9 @@ test.beforeEach((t) => { }); test.afterEach.always(() => { - // Clear nock + // Clear nock and testdouble nock.cleanAll(); + td.reset(); }); test.serial("Publish a release", async (t) => { @@ -666,3 +667,75 @@ test.serial("Publish a release with error response", async (t) => { t.is(error.message, `Response code 499 (Something went wrong)`); t.true(gitlab.isDone()); }); + +test.serial("Publish a release to CI catalog", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { publishToCatalog: true }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(200); + + const execa = (await td.replaceEsm("execa")).execa; + td.when( + execa("glab", ["repo", "publish", "catalog", nextRelease.gitTag], { + cwd: undefined, + timeout: 30000, + env: { GITLAB_TOKEN: env.GITLAB_TOKEN }, + }) + ).thenResolve(); + const publishWithMockExeca = (await import("../lib/publish.js")).default; + await publishWithMockExeca(pluginConfig, { env, options, nextRelease, logger: t.context.logger }); + t.deepEqual(t.context.log.args[1], ["Published tag %s to the CI catalog", nextRelease.gitTag]); + t.true(gitlab.isDone()); +}); + +test.serial("Publish a release to CI catalog with error", async (t) => { + const owner = "test_user"; + const repo = "test_repo"; + const env = { GITLAB_TOKEN: "gitlab_token" }; + const pluginConfig = { publishToCatalog: true }; + const nextRelease = { gitHead: "123", gitTag: "v1.0.0", notes: "Test release note body" }; + const options = { repositoryUrl: `https://gitlab.com/${owner}/${repo}.git` }; + const encodedProjectPath = encodeURIComponent(`${owner}/${repo}`); + const gitlab = authenticate(env) + .post(`/projects/${encodedProjectPath}/releases`, { + tag_name: nextRelease.gitTag, + description: nextRelease.notes, + assets: { + links: [], + }, + }) + .reply(200); + + const execa = (await td.replaceEsm("execa")).execa; + const execaError = new Error("test"); + td.when( + execa("glab", ["repo", "publish", "catalog", nextRelease.gitTag], { + cwd: undefined, + timeout: 30000, + env: { GITLAB_TOKEN: env.GITLAB_TOKEN }, + }) + ).thenReject(execaError); + const publishWithMockedExeca = (await import("../lib/publish.js")).default; + const error = await t.throwsAsync( + publishWithMockedExeca(pluginConfig, { env, options, nextRelease, logger: t.context.logger }) + ); + t.deepEqual(t.context.error.args[0], [ + "An error occurred while publishing tag %s to the CI catalog:\n%O", + nextRelease.gitTag, + execaError, + ]); + t.is(error.message, execaError.message); + t.true(gitlab.isDone()); +}); diff --git a/test/resolve-config.test.js b/test/resolve-config.test.js index 525e9e48..c58f3b39 100644 --- a/test/resolve-config.test.js +++ b/test/resolve-config.test.js @@ -18,6 +18,7 @@ const defaultOptions = { assignee: undefined, proxy: {}, retryLimit: 3, + publishToCatalog: false, }; test("Returns user config", (t) => {