diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e7b1910bc6c37a6964ea5a27c23bd204bb2fe0d..a12216d22ecd342d78c3e3cdc33cf6ddb24d80e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,44 @@ -# [3.9.0](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/semantic-release/compare/3.8.3...3.9.0) (2024-05-13) +# [3.11.0](https://gitlab.com/to-be-continuous/semantic-release/compare/3.10.3...3.11.0) (2024-06-02) ### Features -* add SEMREL_REF to run semantic-release on a wider number of branches alongside info-on 'semrel' to use this variable ([74288af](https://git.code.tecnalia.com/smartdatalab/public/ci-cd-components/semantic-release/commit/74288afbe3fb22ec8c973b228755243b012f998a)) +* add support for configuring a commit specification (e.g. "conventional commits") ([c4519fd](https://gitlab.com/to-be-continuous/semantic-release/commit/c4519fdb1100437dced3ba2bf93c8c069545f303)) + +## [3.10.3](https://gitlab.com/to-be-continuous/semantic-release/compare/3.10.2...3.10.3) (2024-06-02) + + +### Bug Fixes + +* npm cache and add yq cache ([1fc7b1a](https://gitlab.com/to-be-continuous/semantic-release/commit/1fc7b1ac6460c72e53b386b456997a9aa84ece35)) + +## [3.10.2](https://gitlab.com/to-be-continuous/semantic-release/compare/3.10.1...3.10.2) (2024-06-02) + + +### Bug Fixes + +* provide a node-based implementation to retrieve url secrets ([f4e5a22](https://gitlab.com/to-be-continuous/semantic-release/commit/f4e5a225aa9816db907dc432cd842d86918ae838)), closes [#43](https://gitlab.com/to-be-continuous/semantic-release/issues/43) + +## [3.10.1](https://gitlab.com/to-be-continuous/semantic-release/compare/3.10.0...3.10.1) (2024-05-28) + + +### Bug Fixes + +* install gpg ([9533525](https://gitlab.com/to-be-continuous/semantic-release/commit/9533525aa8143bf93e84e41aaf4aed82ab01db15)) + +# [3.10.0](https://gitlab.com/to-be-continuous/semantic-release/compare/3.9.1...3.10.0) (2024-05-20) + + +### Features + +* use slim image by default (shortens job execution time) ([8dbd5da](https://gitlab.com/to-be-continuous/semantic-release/commit/8dbd5da4b489492523e9c678fa1c2b19dcd65283)) + +## [3.9.1](https://gitlab.com/to-be-continuous/semantic-release/compare/3.9.0...3.9.1) (2024-05-18) + + +### Bug Fixes + +* semantic-release don't run on prod_ref ([49217b4](https://gitlab.com/to-be-continuous/semantic-release/commit/49217b4dfcfe2cb6f5bea72cce10cb2af2a95d59)) # [3.9.0](https://gitlab.com/to-be-continuous/semantic-release/compare/3.8.3...3.9.0) (2024-05-10) diff --git a/README.md b/README.md index 4b6f9fd67807478bb0d1dbe38af6f5698448d134..568186c8a03b653a257d27c39b48bb78f5313801 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Add the following to your `gitlab-ci.yml`: ```yaml include: # 1: include the component - - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.9.0 + - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.10.3 # 2: set/override component inputs inputs: changelog-enabled: true # ⚠ this is only an example @@ -34,7 +34,7 @@ Add the following to your `gitlab-ci.yml`: include: # 1: include the template - project: 'to-be-continuous/semantic-release' - ref: '3.9.0' + ref: '3.10.3' file: '/templates/gitlab-ci-semrel.yml' variables: @@ -48,7 +48,7 @@ The semantic-release template uses some global configuration used throughout all | Input / Variable | Description | Default value | | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | -| `image` / `SEMREL_IMAGE` | The Docker image used to run semantic-release | `registry.hub.docker.com/library/node:latest` | +| `image` / `SEMREL_IMAGE` | The Docker image used to run semantic-release | `registry.hub.docker.com/library/node:lts-slim` | | `version` / `SEMREL_VERSION` | The [semantic-release](https://www.npmjs.com/package/semantic-release) version to use | `latest` | | `exec-version` / `SEMREL_EXEC_VERSION` | The [@semantic-release/exec](https://www.npmjs.com/package/@semantic-release/exec) version to use | `latest` | | :lock: `GITLAB_TOKEN` | A GitLab [project access token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) or [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) with `api`, `read_repository` and `write repository` scopes. :warning: This variable is **mandatory** and [defined by `semantic-release`](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#push-access-to-the-remote-repository) itself. | _none_ | @@ -92,7 +92,7 @@ As specified in the previous chapter, these variables are only used to generated | `changelog-title` / `SEMREL_CHANGELOG_TITLE` | [changelogTitle @semantic-release/changelog option](https://github.com/semantic-release/changelog#options). You might want to use markdown format (for example `# MyApp Changelog`). | _none_ | | `dry-run` / `SEMREL_DRY_RUN` | Activate the [dryRun semantic-release option](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#dryrun) if present. | _none_ | | `auto-release-enabled` / `SEMREL_AUTO_RELEASE_ENABLED` | When set to `true` the job start automatically. When not set (default), the job is manual. | _none_ | -| `branches-ref` / `SEMREL_BRANCHES_REF` | Regular expression pattern matching branches from which releases should happen (should match your [semantic-release configuration](https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches)) | `$PROD_REF` ([global _to be continuous_ variable](https://to-be-continuous.gitlab.io/doc/usage/#production-and-integration-branches)) | +| `branches-ref` / `SEMREL_BRANCHES_REF` | Regular expression pattern matching branches from which releases should happen (should match your [semantic-release configuration](https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches)) | `/^(master|main)$/` | | `tag-format` / `SEMREL_TAG_FORMAT` | [tagFormat semantic-release option](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#tagformat). :warning: don't forget to double the `$` character so it is not interpreted by GitLab. | `$${version}` | | `hooks-dir` / `SEMREL_HOOKS_DIR` | [Hook scripts](#hook_scripts) folder. | `.` | | `commit-message` / `SEMREL_COMMIT_MESSAGE` | Add a custom commit message based on [semantic-release/git option](https://github.com/semantic-release/git#message). | _none_ (uses semantic-release default commit message) | @@ -186,6 +186,29 @@ This job can be enabled by defining the `SEMREL_INFO_ON` variable: * `protected` to enable on protected references * `all` to enable on all Git references. :warning: Beware that this job requires the `GITLAB_TOKEN` variable so you must unprotect it (this will make privilege escalation possible from developer to maintainer). +#### Semantic Release Commit Analyzer and Release Notes Configuration + +Semantic Release determines the semantic version, major.minor.patch, with the use of `@semantic-release/commit-analyzer` and `@semantic-release/release-notes-generator` `presets`. The [**default** preset is `angular`](https://github.com/semantic-release/semantic-release?tab=readme-ov-file#commit-message-format). +The default _may_ lead to unexpected versioning or release notes, especially when not in an Angular project nor using the Angular standard. + +The commit message parser may be changed by defining the `commit-spec` / `SEMREL_COMMIT_SPEC` variable: + +| Input / Variable | Description | Default | +| ------------------------------------------- | ----------- | ------- | +| `commit-spec` / `SEMREL_COMMIT_SPEC` | commit specification `preset` (possible values: `angular`, `codemirror`, `ember`, `eslint`, `express`, `jquery`, `jshint`, `conventionalcommits` (`cc` short form supported)) | `angular` | + +**Conventional Commit Specification** + +The `preset` of `conventionalcommits` (or `cc`) is a good option for most users. The [specification is well defined and documented](https://www.conventionalcommits.org/en/v1.0.0/) and compatible with tools like [Husky](https://typicode.github.io/husky/) and [commitlint](https://commitlint.js.org/). Semantic Release has plans to make `conventionalcommits` the default in the future. + +**Commit Message Controls** + +The `commit-spec` / `SEMREL_COMMIT_SPEC` value installs the parser requirement for Semantic Release only. Adherence to a specification with commit message controls is not provided. Angular and Conventional Commits are widely supported by commitlint and [commitizen](https://github.com/commitizen), though additional `devDependencies` and configuration files may be required, please review the tooling documentation for more information. + +**Note on supporting Semantic Release versions** + +If the version of Semantic Release is pinned using [`SEMREL_VERSION`](#global-configuration) prior to v24, automated versioning via commit messaging may fail in unexpected ways. See [conventional-changelog-conventionalcommits v8.0.0 breaks semantic release](https://github.com/semantic-release/release-notes-generator/issues/633) or consider upgrading the pinned version to v24 or better to restore behaviors. + ## Secrets management Here are some advices about your **secrets** (variables marked with a :lock:): @@ -201,9 +224,125 @@ Here are some advices about your **secrets** (variables marked with a :lock:): 3. Don't forget to escape special characters (ex: `$` -> `$$`). 4. You can also manage secrets using Vault variant +## Using semantic-release with other to-be-continuous templates + +The semantic-release template has been designed to interoperate gracefully with release-capable to-be-continuous templates. + +Unfortunaltely, there isn't one single configuration that fits all needs. +Instead, the semantic-release template configuration will have to be adapted to your case. + +There are actually 2 questions that will determine the required configuration: + +1. which [Delivery Mode](https://to-be-continuous.gitlab.io/doc/understand/#delivery-modes) are you using in your project? + * _Application Deployment_ mode should trigger the release directly from your production branch (`main` or `master` by default), + * _Software Distribution_ mode should trigger the release through a tag pipeline. +2. does the release involve **changing files in your repository** (and therefore creating a Git commit)? + * that will be the case if you use plugins such as [@semantic-release/changelog](https://github.com/semantic-release/changelog) or [semantic-release-replace](https://github.com/jpoehnelt/semantic-release-replace-plugin) + +### Case 1: _Application Deployment_ mode + +When using the _Application Deployment_ delivery mode in your project, the release should be triggered directly from the production branch (`main` or `master` by default). + +In that case you'll need to: + +1. enable the [semantic-release info job](#semantic-release-info-job),<br/> + _this is the job that will provide next release information to the other template(s)_ + * by setting `info-on` input / `SEMREL_INFO_ON` variable to `prod` (or any suitable non-empty value) +2. disable the [semantic-release job](#semantic-release-job),<br/> + _the release will be handled by other template(s) directly from the production branch_ + * by setting `release-disabled` input / `SEMREL_RELEASE_DISABLED` variable to `true` +3. make sure the other template(s) provide a semantic-release integration to perform the release from the semantic-release info job. + Templates supporting it: + * Docker, + * Helm, + * Maven, + * Python, + * S2I. + +### Case 2: _Software Distribution_ mode without any Git commit + +This is the easiest case as nothing specific has to be done to address it: + +* by default the semantic-release will analyse each commit on your production branch, and will possibly create a Git tag (but no Git commit) if it determined a release has to be performed, +* the Git tag will trigger a tag pipeline during which every to-be-continuous template will take care of publishing its versioned package (using the Git tag as the version) to an appropriate packages repository. + +### Case 3: _Software Distribution_ mode with a Git commit + +This case will occur if you configure semantic-release to modify one or several files in your Git repository (ex: `pom.xml`, `pyproject.toml`, `CHANGELOG.md`, `README.md`...) + +In that case, when semantic-release determines a release is required, it will: + +* modify the files, +* create a Git commit with the changes, +* create a Git tag with the next release version, +* push the commit + the tag. + +Problem: by default, semantic-release creates a Git commit with comment `chore(release): ${nextRelease.version} [skip ci]`.\ +:information_source: The `[skip ci]` part is problematic as it prevents GitLab from triggering the tag pipeline, therefore preventing other to-be-continuous templates from publishing their versioned packages. + +To fix this, you'll have to override the default semantic-release Git commit comment in order not to prevent the tag pipeline from being triggered. +With this done: + +* the semantic-release will analyse each commit on your production branch, and will possibly create a Git tag if it determined a release has to be performed, +* the Git tag will trigger a tag pipeline during which every to-be-continuous template will take care of publishing its versioned package (using the Git tag as the version) to an appropriate packages repository. + +#### How to override the Git commit comment + +In most cases it is recommended to use `chore(release): ${nextRelease.version} [skip ci on prod]` as message template.\ +:information_source: the important part is `[skip ci on prod]` that prevents GitLab from triggering the pipeline on your production branch only, **but not the tag pipeline**. + +#### Using a configuration file + +If you're configuring semantic-release with a configuration file in your repository, then the Git commit message has to be configured in the [@semantic-release/git](https://github.com/semantic-release/git#message) plugin section. + +Here is a `.releaserc.yaml` configuration example that auto-generates the changelog file, and also replaces the project version in the `pyproject.toml` using the [semantic-release-replace](https://github.com/jpoehnelt/semantic-release-replace-plugin) plugin: + +```yaml +plugins: + # GitLab support + - '@semantic-release/gitlab' + # analyses the Git commits + - '@semantic-release/commit-analyzer' + # generates the release note from the Git commit messages + - '@semantic-release/release-notes-generator' + # generates the CHANGELOG.md file + - '@semantic-release/changelog' + # emulates bumpversion (replaces 'version' in pyproject.toml) + - - semantic-release-replace-plugin + - replacements: + - files: + - pyproject.toml + from: + - ^version *= *"\d+\.\d+\.\d+" + to: 'version = "${nextRelease.version}"' + countMatches: true + # git commit/push modified files + - - '@semantic-release/git' + - assets: + - 'CHANGELOG.md' + - 'pyproject.toml' + # the commit MUST trigger a pipeline on tag (to perform publish jobs) + # can be skipped on prod branch + message: 'chore(release): ${nextRelease.version} [skip ci on prod]' +branches: + - main + - master +tagFormat: '${version}' +``` + +#### Using implicit configuration + +If you're not configuring semantic-release with a configuration file (but using implicit configuration provided by the template), then the Git commit message can be configured with the `commit-message` input / `SEMREL_COMMIT_MESSAGE` variable: + +```yaml +variables: + # the '$' has to be doubled to prevent GitLab from expanding it as a variable + SEMREL_COMMIT_MESSAGE: 'chore(release): $${nextRelease.version} [skip ci on prod]' +``` + ## Variants -The Docker template can be used in conjunction with template variants to cover specific cases. +The semantic-release template can be used in conjunction with template variants to cover specific cases. ### Vault variant @@ -241,9 +380,9 @@ With: ```yaml include: # main template - - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.9.0 + - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.10.3 # Vault variant - - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel-vault@3.9.0 + - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel-vault@3.10.3 inputs: vault-base-url: "https://vault.acme.host/v1" # audience claim for JWT diff --git a/kicker.json b/kicker.json index f159c04dc8be5a2f7f94e04786eeac9b716d6657..1fc4dc569c109f5fef82a4ec293ade9404b58be3 100644 --- a/kicker.json +++ b/kicker.json @@ -10,7 +10,7 @@ { "name": "SEMREL_IMAGE", "description": "The Docker image used to run semantic-release", - "default": "registry.hub.docker.com/library/node:latest" + "default": "registry.hub.docker.com/library/node:lts-slim" }, { "name": "SEMREL_VERSION", @@ -86,7 +86,7 @@ { "name": "SEMREL_BRANCHES_REF", "description": "Regular expression pattern matching branches from which releases should happen (should match your [semantic-release configuration](https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches))", - "default": "$PROD_REF", + "default": "/^(master|main)$/", "advanced": true }, { @@ -112,6 +112,13 @@ "type": "array", "default": [], "advanced": true + }, + { + "name": "SEMREL_COMMIT_SPEC", + "description": "Commit specification `preset` (possible values: `angular`, `atom`, `codemirror`, `ember`, `eslint`, `express`, `jquery`, `jshint`, `conventionalcommits`). The default is `angular`.", + "values": ["angular","codemirror","conventionalcommits","ember","eslint","express","jquery","jshint"], + "default": "angular", + "advanced": true } ] }, diff --git a/templates/gitlab-ci-semrel-vault.yml b/templates/gitlab-ci-semrel-vault.yml index a31fa29900dd912b9b7a3aed105ba085e65d63ea..3fb7c9870c717a4f26c4004edc10d5cc6cba030c 100644 --- a/templates/gitlab-ci-semrel-vault.yml +++ b/templates/gitlab-ci-semrel-vault.yml @@ -22,7 +22,7 @@ variables: .semrel-base: services: - name: "$TBC_TRACKING_IMAGE" - command: ["--service", "semrel", "3.9.0"] + command: ["--service", "semrel", "3.10.3"] - name: "$TBC_VAULT_IMAGE" alias: "vault-secrets-provider" variables: diff --git a/templates/gitlab-ci-semrel.yml b/templates/gitlab-ci-semrel.yml index f0de1a004b685b47f4a424da6481b63e85fd629c..aa60c29b8ffacce7056f33804d9b30163b0478b6 100644 --- a/templates/gitlab-ci-semrel.yml +++ b/templates/gitlab-ci-semrel.yml @@ -18,13 +18,13 @@ spec: inputs: image: description: The Docker image used to run semantic-release - default: registry.hub.docker.com/library/node:latest + default: registry.hub.docker.com/library/node:lts-slim version: description: The [semantic-release](https://www.npmjs.com/package/semantic-release) version to use default: latest branches-ref: description: Regular expression pattern matching branches from which releases should happen (should match your [semantic-release configuration](https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches)) - default: $PROD_REF + default: /^(master|main)$/ exec-version: description: The [@semantic-release/exec](https://www.npmjs.com/package/@semantic-release/exec) version to use default: latest @@ -65,6 +65,18 @@ spec: commit-message: description: '[message @semantic-release/git option](https://github.com/semantic-release/git#message)' default: '' + commit-spec: + description: "Commit specification `preset` (possible values: `angular`, `codemirror`, `ember`, `eslint`, `express`, `jquery`, `jshint`, `conventionalcommits`). The default is `angular`." + options: + - angular + - codemirror + - conventionalcommits + - ember + - eslint + - express + - jquery + - jshint + default: 'angular' info-on: description: Define on which branch(es) the job shall be run options: @@ -134,6 +146,7 @@ variables: SEMREL_COMMIT_MESSAGE: $[[ inputs.commit-message ]] SEMREL_RELEASE_DISABLED: $[[ inputs.release-disabled ]] SEMREL_INFO_ON: $[[ inputs.info-on ]] + SEMREL_COMMIT_SPEC: $[[ inputs.commit-spec ]] # default production ref name (pattern) PROD_REF: /^(master|main)$/ @@ -368,6 +381,16 @@ stages: else log_warn "Failed getting secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" fi + elif command -v node > /dev/null + then + if node -e "const fs=require('fs');function dlFile(url,file,maxRedir=5){return new Promise((resolve,reject)=>{let redirCount=0;const req=require(url.split(':')[0]).get(url,res=>{res.statusCode>=300&&res.statusCode<400&&res.headers.location&&redirCount<maxRedir?(redirCount++,console.log('Follow redirect ('+redirCount+'): '+res.headers.location),dlFile(res.headers.location,file,maxRedir).then(resolve).catch(reject)):200===res.statusCode?(res.pipe(fs.createWriteStream(file)).on('finish',()=>resolve()),res.on('error',reject)):reject(new Error('HTTP error: '+res.statusCode))});req.on('error',reject)})}dlFile('$url','$decoded').then(()=>{console.log('Download complete'),process.exit(0)}).catch(e=>{console.error('Error:',e),process.exit(1)});" 2> "${errors}" + then + # shellcheck disable=SC2086 + export ${name}="$(cat ${decoded})" + log_info "Successfully dl'd secret \\e[33;1m${name}\\e[0m" + else + log_warn "Failed getting secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" + fi else log_warn "Couldn't get secret \\e[33;1m${name}\\e[0m: no http client found" fi @@ -383,6 +406,55 @@ stages: done } + function download_file() { + if command -v wget &> /dev/null + then + wget "$1" -O "$2" + elif command -v curl &> /dev/null + then + curl -sfL "$1" -o "$2" + elif command -v node &> /dev/null + then + node -e "const fs=require('fs');function dlFile(url,file,maxRedir=5){return new Promise((resolve,reject)=>{let redirCount=0;const req=require(url.split(':')[0]).get(url,res=>{res.statusCode>=300&&res.statusCode<400&&res.headers.location&&redirCount<maxRedir?(redirCount++,console.log('Follow redirect ('+redirCount+'): '+res.headers.location),dlFile(res.headers.location,file,maxRedir).then(resolve).catch(reject)):200===res.statusCode?(res.pipe(fs.createWriteStream(file)).on('finish',()=>resolve()),res.on('error',reject)):reject(new Error('HTTP error: '+res.statusCode))});req.on('error',reject)})}dlFile('$1','$2').then(()=>{console.log('Download complete'),process.exit(0)}).catch(e=>{console.error('Error:',e),process.exit(1)});" + else + fail "wget, curl or node required" + fi + } + + function github_get_latest_version() { + if command -v curl &> /dev/null + then + curl -sSf -I "https://github.com/$1/releases/latest" | awk -F '/' -v RS='\r\n' '/location:/ {print $NF}' + elif command -v node &> /dev/null + then + node -e "const https=require('https'); const options={hostname:'github.com', path:'/$1/releases/latest', method:'HEAD'}; https.request(options, (res) => {tokens=res.headers.location.split('/'); console.log(tokens[tokens.length-1]); res.req.destroy()}).end();" + else + fail "curl or node required" + fi + } + + function maybe_install_packages() { + if command -v apt-get > /dev/null + then + # Debian + if ! dpkg --status "$@" > /dev/null + then + apt-get update + apt-get install --no-install-recommends --yes --quiet "$@" + fi + elif command -v apk > /dev/null + then + # Alpine + if ! apk info --installed "$@" > /dev/null + then + apk add --no-cache "$@" + fi + else + log_error "... didn't find any supported package manager to install $*" + exit 1 + fi + } + function extract_release_config_from_package_json() { package_json="./package.json" if [[ -f "${package_json}" ]]; then @@ -426,6 +498,7 @@ stages: else debug="false" fi + commitPresetConfig=$(generate_commit_preset_conf) changelogPluginConfig=$(generate_changelog_plugin_conf) execPluginConfig=$(generate_exec_plugin_conf) gitPluginConfig=$(generate_git_plugin_conf) @@ -435,8 +508,10 @@ stages: echo "tagFormat: '${SEMREL_TAG_FORMAT}'" echo "" echo "plugins: " - echo " - '@semantic-release/commit-analyzer'" - echo " - '@semantic-release/release-notes-generator'" + echo " - - '@semantic-release/commit-analyzer'" + echo "${commitPresetConfig}" + echo " - - '@semantic-release/release-notes-generator'" + echo "${commitPresetConfig}" echo " - '@semantic-release/gitlab'" echo "${changelogPluginConfig}" echo "${execPluginConfig}" @@ -469,9 +544,35 @@ stages: done <<< $(yq eval ".plugins[]" "${semrelConfigFile}" -o=json --indent 0) # shellcheck disable=SC2086 - npm install -g "semantic-release@${SEMREL_VERSION}" ${required_plugins} + npm install --global "semantic-release@${SEMREL_VERSION}" ${required_plugins} + + if [[ ! -f "${SEMREL_REQUIRED_PLUGINS_FILE}" && -n "${SEMREL_COMMIT_SPEC}" ]]; then + case "$SEMREL_COMMIT_SPEC" in + cc) + SEMREL_COMMIT_SPEC=conventionalcommits + ;; + esac + npm install --global "conventional-changelog-$SEMREL_COMMIT_SPEC" + fi + + if [[ -n "$TRACE" ]]; then + log_info "Installed devDependencies..." + npm pkg get devDependencies + log_info "Globally installed packages..." + npm list --global + fi } + # this script console output is inserted in generated file: DO NOT ADD LOGS + function generate_commit_preset_conf() { + if [[ -n "${SEMREL_COMMIT_SPEC}" ]]; then + if [[ "${SEMREL_COMMIT_SPEC}" == "cc" ]]; then + conventionalCommits="conventionalcommits" + fi + echo " - preset: '${conventionalCommits:-$SEMREL_COMMIT_SPEC}'" + fi + } + # this script console output is inserted in generated file: DO NOT ADD LOGS function generate_changelog_plugin_conf() { if [[ "${SEMREL_CHANGELOG_ENABLED}" = "true" ]]; then @@ -561,13 +662,26 @@ stages: fi } - function install_yq() { + function maybe_install_yq() { if ! command -v yq > /dev/null then - yq_binary=$1 - yq_version=$2 + yq_version=$(github_get_latest_version mikefarah/yq) + yq_binary=yq_linux_amd64 yq_url="https://github.com/mikefarah/yq/releases/download/${yq_version}/${yq_binary}.tar.gz" - wget -q "${yq_url}" -O - | tar xz && mv "${yq_binary}" /usr/bin/yq + yq_cache="$XDG_CACHE_HOME/yq-$(echo "$yq_url" | md5sum | cut -d" " -f1)" + + if [[ -f "$yq_cache" ]] + then + log_info "yq found in cache: reuse" + else + log_info "yq not found in cache: download" + log_info "Download latest yq version: \\e[32m$yq_url\\e[0m" + download_file "${yq_url}" "${yq_binary}.tar.gz" + tar xvf "${yq_binary}.tar.gz" + mkdir -p "$XDG_CACHE_HOME" + mv "${yq_binary}" "$yq_cache" + fi + ln -s "$yq_cache" /usr/bin/yq fi } @@ -633,7 +747,7 @@ stages: cat ".releaserc" fi - npm install -g "semantic-release@${SEMREL_VERSION}" "@semantic-release/exec@${SEMREL_EXEC_VERSION}" + npm install --global "semantic-release@${SEMREL_VERSION}" "@semantic-release/exec@${SEMREL_EXEC_VERSION}" semantic-release --dry-run # Rollback temporary semantic-release configuration @@ -688,19 +802,31 @@ stages: image: $SEMREL_IMAGE services: - name: "$TBC_TRACKING_IMAGE" - command: ["--service", "semrel", "3.9.0"] + command: ["--service", "semrel", "3.10.3"] before_script: - !reference [.semrel-scripts] - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}" + # install git and OpenSSH + - maybe_install_packages ca-certificates git openssh-client gpg + - maybe_install_yq - cd "${SEMREL_CONFIG_DIR}" - - install_yq "yq_linux_amd64" "v4.21.1" - prepare_semantic_release - install_semantic_release_plugins + variables: + # download cache + XDG_CACHE_HOME: "$CI_PROJECT_DIR/.cache" + # NPM cache + npm_config_cache: "$CI_PROJECT_DIR/.npm" + # Cache downloaded dependencies and plugins between builds. + # To keep cache across branches add 'key: "$CI_JOB_NAME"' cache: # cache shall be per branch per template key: "$CI_COMMIT_REF_SLUG-SEMREL" + when: always paths: - - .npm/ + - "$CI_PROJECT_DIR/.npm" + - "$XDG_CACHE_HOME" + semantic-release-info: extends: .semrel-base