Skip to content
Snippets Groups Projects
gitlab-ci-semrel.yml 21.5 KiB
Newer Older
Pierre Smeyers's avatar
Pierre Smeyers committed
# =========================================================================================
Pierre Smeyers's avatar
Pierre Smeyers committed
# Copyright (C) 2021 Orange & contributors
Pierre Smeyers's avatar
Pierre Smeyers committed
#
# This program is free software; you can redistribute it and/or modify it under the terms 
# of the GNU Lesser General Public License as published by the Free Software Foundation; 
# either version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with this 
# program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth 
# Floor, Boston, MA  02110-1301, USA.
# =========================================================================================
variables:
  # Default Docker image (use a public image - can be overridden)
  SEMREL_IMAGE: "node:latest"
  SEMREL_HOOKS_DIR: "."
  SEMREL_TAG_FORMAT: "$${version}"
  # SEMREL_INFO_ENABLED
  SEMREL_INFO_FILE: ".semrel-info.dotenv"
  
  # default production ref name (pattern)
  PROD_REF: '/^(master|main)$/'
  SEMREL_REQUIRED_PLUGINS_FILE: "semrel-required-plugins.txt"

Pierre Smeyers's avatar
Pierre Smeyers committed
  # undocumented (for internal use only)
  SEMREL_VERIFY_CONDITIONS_CMD: "verify-conditions.sh"
  SEMREL_VERIFY_RELEASE_CMD: "verify-release.sh"
  SEMREL_PREPARE_CMD: "prepare.sh"
  SEMREL_PUBLISH_CMD: "publish.sh"
  SEMREL_SUCCESS_CMD: "success.sh"
  SEMREL_FAIL_CMD: "fail.sh"
  SEMREL_CONFIG_DIR: "."
Pierre Smeyers's avatar
Pierre Smeyers committed

stages:
  - publish

.semrel-scripts: &semrel-scripts |
  # BEGSCRIPT
  set -e

  function log_info() {
      echo -e "[\\e[1;94mINFO\\e[0m] $*"
  }

  function log_warn() {
      echo -e "[\\e[1;93mWARN\\e[0m] $*"
  }

  function log_error() {
      echo -e "[\\e[1;91mERROR\\e[0m] $*"
  }

  function fail() {
    log_error "$*"
    exit 1
  }

  function assert_defined() {
    if [[ -z "$1" ]]
    then
      log_error "$2"
      exit 1
    fi
  }

  function install_ca_certs() {
    certs=$1
    if [[ -z "$certs" ]]
    then
      return
    fi

    # import in system
    if echo "$certs" >> /etc/ssl/certs/ca-certificates.crt
    then
      log_info "CA certificates imported in \\e[33;1m/etc/ssl/certs/ca-certificates.crt\\e[0m"
    fi
    if echo "$certs" >> /etc/ssl/cert.pem
    then
      log_info "CA certificates imported in \\e[33;1m/etc/ssl/cert.pem\\e[0m"
    fi

    # import in Java keystore (if keytool command found)
    if command -v keytool > /dev/null
    then
      # shellcheck disable=SC2046
      javahome=${JAVA_HOME:-$(dirname $(readlink -f $(command -v java)))/..}
      # shellcheck disable=SC2086
      keystore=${JAVA_KEYSTORE_PATH:-$(ls -1 $javahome/jre/lib/security/cacerts 2>/dev/null || ls -1 $javahome/lib/security/cacerts 2>/dev/null || echo "")}
      if [[ -f "$keystore" ]]
      then
        storepass=${JAVA_KEYSTORE_PASSWORD:-changeit}
        nb_certs=$(echo "$certs" | grep -c 'END CERTIFICATE')
        log_info "importing $nb_certs certificates in Java keystore \\e[33;1m$keystore\\e[0m..."
        for idx in $(seq 0 $((nb_certs - 1)))
        do
          # TODO: use keytool option -trustcacerts ?
          if echo "$certs" | awk "n==$idx { print }; /END CERTIFICATE/ { n++ }" | keytool -noprompt -import -alias "imported CA Cert $idx" -keystore "$keystore" -storepass "$storepass"
          then
            log_info "... CA certificate [$idx] successfully imported"
          else
            log_warn "... Failed importing CA certificate [$idx]: abort"
            return
          fi
        done
      else
        log_warn "Java keystore \\e[33;1m$keystore\\e[0m not found: could not import CA certificates"
      fi
    fi
  }

  function unscope_variables() {
    _scoped_vars=$(env | awk -F '=' "/^scoped__[a-zA-Z0-9_]+=/ {print \$1}" | sort)
    if [[ -z "$_scoped_vars" ]]; then return; fi
    log_info "Processing scoped variables..."
    for _scoped_var in $_scoped_vars
    do
      _fields=${_scoped_var//__/:}
      _condition=$(echo "$_fields" | cut -d: -f3)
      case "$_condition" in
      if) _not="";;
      ifnot) _not=1;;
      *)
        log_warn "... unrecognized condition \\e[1;91m$_condition\\e[0m in \\e[33;1m${_scoped_var}\\e[0m"
        continue
      ;;
      esac
      _target_var=$(echo "$_fields" | cut -d: -f2)
      _cond_var=$(echo "$_fields" | cut -d: -f4)
      _cond_val=$(eval echo "\$${_cond_var}")
      _test_op=$(echo "$_fields" | cut -d: -f5)
      case "$_test_op" in
      defined)
        if [[ -z "$_not" ]] && [[ -z "$_cond_val" ]]; then continue; 
        elif [[ "$_not" ]] && [[ "$_cond_val" ]]; then continue; 
        fi
        ;;
      equals|startswith|endswith|contains|in|equals_ic|startswith_ic|endswith_ic|contains_ic|in_ic)
        # comparison operator
        # sluggify actual value
        _cond_val=$(echo "$_cond_val" | tr '[:punct:]' '_')
        # retrieve comparison value
        _cmp_val_prefix="scoped__${_target_var}__${_condition}__${_cond_var}__${_test_op}__"
Cédric OLIVIER's avatar
Cédric OLIVIER committed
        _cmp_val=${_scoped_var#"$_cmp_val_prefix"}
        # manage 'ignore case'
        if [[ "$_test_op" == *_ic ]]
        then
          # lowercase everything
          _cond_val=$(echo "$_cond_val" | tr '[:upper:]' '[:lower:]')
          _cmp_val=$(echo "$_cmp_val" | tr '[:upper:]' '[:lower:]')
        fi
        case "$_test_op" in
        equals*)
          if [[ -z "$_not" ]] && [[ "$_cond_val" != "$_cmp_val" ]]; then continue; 
          elif [[ "$_not" ]] && [[ "$_cond_val" == "$_cmp_val" ]]; then continue; 
          fi
          ;;
        startswith*)
          if [[ -z "$_not" ]] && [[ "$_cond_val" != "$_cmp_val"* ]]; then continue; 
          elif [[ "$_not" ]] && [[ "$_cond_val" == "$_cmp_val"* ]]; then continue; 
          fi
          ;;
        endswith*)
          if [[ -z "$_not" ]] && [[ "$_cond_val" != *"$_cmp_val" ]]; then continue; 
          elif [[ "$_not" ]] && [[ "$_cond_val" == *"$_cmp_val" ]]; then continue; 
          fi
          ;;
        contains*)
          if [[ -z "$_not" ]] && [[ "$_cond_val" != *"$_cmp_val"* ]]; then continue; 
          elif [[ "$_not" ]] && [[ "$_cond_val" == *"$_cmp_val"* ]]; then continue; 
          fi
          ;;
        in*)
          if [[ -z "$_not" ]] && [[ "__${_cmp_val}__" != *"__${_cond_val}__"* ]]; then continue; 
          elif [[ "$_not" ]] && [[ "__${_cmp_val}__" == *"__${_cond_val}__"* ]]; then continue; 
          fi
          ;;
        esac
        ;;
      *)
        log_warn "... unrecognized test operator \\e[1;91m${_test_op}\\e[0m in \\e[33;1m${_scoped_var}\\e[0m"
        continue
        ;;
      esac
      # matches
      _val=$(eval echo "\$${_target_var}")
      log_info "... apply \\e[32m${_target_var}\\e[0m from \\e[32m\$${_scoped_var}\\e[0m${_val:+ (\\e[33;1moverwrite\\e[0m)}"
      _val=$(eval echo "\$${_scoped_var}")
      export "${_target_var}"="${_val}"
    done
    log_info "... done"
  }

Pierre Smeyers's avatar
Pierre Smeyers committed
  # evaluate and export a secret
  # - $1: secret variable name
  function eval_secret() {
    name=$1
    value=$(eval echo "\$${name}")
    case "$value" in
    @b64@*)
      decoded=$(mktemp)
      errors=$(mktemp)
      if echo "$value" | cut -c6- | base64 -d > "${decoded}" 2> "${errors}"
      then
        # shellcheck disable=SC2086
        export ${name}="$(cat ${decoded})"
        log_info "Successfully decoded base64 secret \\e[33;1m${name}\\e[0m"
      else
        fail "Failed decoding base64 secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")"
      fi
      ;;
    @hex@*)
      decoded=$(mktemp)
      errors=$(mktemp)
      if echo "$value" | cut -c6- | sed 's/\([0-9A-F]\{2\}\)/\\\\x\1/gI' | xargs printf > "${decoded}" 2> "${errors}"
      then
        # shellcheck disable=SC2086
        export ${name}="$(cat ${decoded})"
        log_info "Successfully decoded hexadecimal secret \\e[33;1m${name}\\e[0m"
      else
        fail "Failed decoding hexadecimal secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")"
      fi
      ;;
    @url@*)
      url=$(echo "$value" | cut -c6-)
      if command -v curl > /dev/null
      then
        decoded=$(mktemp)
        errors=$(mktemp)
        if curl -s -S -f --connect-timeout 5 -o "${decoded}" "$url" 2> "${errors}"
        then
          # shellcheck disable=SC2086
          export ${name}="$(cat ${decoded})"
          log_info "Successfully curl'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}")"
Pierre Smeyers's avatar
Pierre Smeyers committed
        fi
      elif command -v wget > /dev/null
      then
        decoded=$(mktemp)
        errors=$(mktemp)
        if wget -T 5 -O "${decoded}" "$url" 2> "${errors}"
        then
          # shellcheck disable=SC2086
          export ${name}="$(cat ${decoded})"
          log_info "Successfully wget'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}")"
Pierre Smeyers's avatar
Pierre Smeyers committed
        fi
      else
        log_warn "Couldn't get secret \\e[33;1m${name}\\e[0m: no http client found"
Pierre Smeyers's avatar
Pierre Smeyers committed
      fi
      ;;
    esac
  }

  function eval_all_secrets() {
    encoded_vars=$(env | grep -v '^scoped__' | awk -F '=' '/^[a-zA-Z0-9_]*=@(b64|hex|url)@/ {print $1}')
Pierre Smeyers's avatar
Pierre Smeyers committed
    for var in $encoded_vars
    do
      eval_secret "$var"
    done
  }

  function extract_release_config_from_package_json() {
    package_json="./package.json"
    if [[ -f "${package_json}" ]]; then
      release_config=$(node -pe "JSON.stringify(require('${package_json}').release, null, 2)")
      case "$release_config" in
        "undefined"|"null") release_config="" ;;
      esac
      echo "$release_config"
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
  }

  function prepare_semantic_release() {
    if [[ -f ".releaserc" ]]; then
      log_info "\\e[33;1m.releaserc\\e[0m file found"
      semrelConfigFile=".releaserc"
    elif [[ -f ".releaserc.yml" ]]; then
      log_info "\\e[33;1m.releaserc.yml\\e[0m file found"
      semrelConfigFile=".releaserc.yml"
    elif [[ -f ".releaserc.yaml" ]]; then
      log_info "\\e[33;1m.releaserc.yaml\\e[0m file found"
      semrelConfigFile=".releaserc.yaml"
    elif [[ -f ".releaserc.json" ]]; then
      log_info "\\e[33;1m.releaserc.json\\e[0m file found"
      semrelConfigFile=".releaserc.json"
    elif [[ -f ".releaserc.js" ]]; then
      log_info "\\e[33;1m.releaserc.js\\e[0m file found"
      semrelConfigFile=".releaserc.js"
    else
      releaseConfig="$(extract_release_config_from_package_json)"
      if [[ -n "${releaseConfig}" ]]; then
        log_info "release configuration found in \\e[33;1mpackage.json\\e[0m file"
        # exporting release configuration in dedicated file for required plugins installation
        semrelConfigFile=".release_config_from_package_json"
        echo "${releaseConfig}" > "${semrelConfigFile}"
      else
        log_info "semantic release configuration file not found, generating default \\e[33;1m.releaserc\\e[0m"
        semrelConfigFile=".releaserc"
        if [[ -n "$TRACE" ]]; then
          debug="true"
        else
          debug="false"
        fi
        changelogPluginConfig=$(generate_changelog_plugin_conf)
        execPluginConfig=$(generate_exec_plugin_conf)
        gitPluginConfig=$(generate_git_plugin_conf)
        {
          echo "debug: ${debug}"
          echo ""
          echo "tagFormat: '${SEMREL_TAG_FORMAT}'"
Pierre Smeyers's avatar
Pierre Smeyers committed
          echo ""
          echo "plugins: "
          echo "  - '@semantic-release/commit-analyzer'"
          echo "  - '@semantic-release/release-notes-generator'"
          echo "  - '@semantic-release/gitlab'"
Pierre Smeyers's avatar
Pierre Smeyers committed
          echo "${changelogPluginConfig}"
          echo "${execPluginConfig}"
          echo "${gitPluginConfig}"
          echo ""
          echo "branches:"
Pierre Smeyers's avatar
Pierre Smeyers committed
        } > "${semrelConfigFile}"
        cat "${semrelConfigFile}"
      fi
    fi
  function install_semantic_release_plugins() {
Pierre Smeyers's avatar
Pierre Smeyers committed
    log_info "installing required plugins"
    # shellcheck disable=SC2046
    if [[ -f "${SEMREL_REQUIRED_PLUGINS_FILE}" ]]; then
      while IFS= read -r line || [[ -n "$line" ]]
      do
        required_plugins="${required_plugins} $line"
      done <<< $(cat "${SEMREL_REQUIRED_PLUGINS_FILE}")
    fi

Pierre Smeyers's avatar
Pierre Smeyers committed
    # shellcheck disable=SC2046
    while IFS= read -r line || [[ -n "$line" ]]
    do
      plugin=$(echo "$line" | cut -d\" -f2)
      required_plugins="${required_plugins} $plugin"
    done <<< $(yq eval ".plugins[]" "${semrelConfigFile}" -o=json --indent 0)

    # shellcheck disable=SC2086
    npm install -g semantic-release ${required_plugins}
Pierre Smeyers's avatar
Pierre Smeyers committed
  }

  # this script console output is inserted in generated file: DO NOT ADD LOGS
  function generate_changelog_plugin_conf() {
    if [[ "${SEMREL_CHANGELOG_ENABLED}" = "true" ]]; then
Pierre Smeyers's avatar
Pierre Smeyers committed
      if [[ -n "${SEMREL_CHANGELOG_FILE}" ]] || [[ -n "${SEMREL_CHANGELOG_TITLE}" ]]; then
        if [[ -n "${SEMREL_CHANGELOG_FILE}" ]]; then
          changeLogConfig="changelogFile: '${SEMREL_CHANGELOG_FILE}'"
Pierre Smeyers's avatar
Pierre Smeyers committed
        fi
        if [[ -n "${SEMREL_CHANGELOG_TITLE}" ]]; then
          changeLogConfig=$(echo -e "${changeLogConfig:+${changeLogConfig}\n      }changelogTitle: '${SEMREL_CHANGELOG_TITLE}'")
Pierre Smeyers's avatar
Pierre Smeyers committed
        fi
        echo "  - - '@semantic-release/changelog'"
        echo "    - ${changeLogConfig}"
Pierre Smeyers's avatar
Pierre Smeyers committed
      else
        echo "  - '@semantic-release/changelog'"
Pierre Smeyers's avatar
Pierre Smeyers committed
      fi
    else
      echo ""
    fi
  }

  # this script console output is inserted in generated file: DO NOT ADD LOGS
  function generate_git_plugin_conf() {
    # git plugin has default changelog file as asset by default so 
    # we need to add it explicitly if the user configured a custom changelogFile
    if [[ "${SEMREL_CHANGELOG_ENABLED}" = "true" ]] && [[ -n "${SEMREL_CHANGELOG_FILE}" ]]; then
      echo "  - - '@semantic-release/git'"
      echo "    - assets:"
      echo "      - '${SEMREL_CHANGELOG_FILE}'"
      echo "      - 'package.json'"
      echo "      - 'package-lock.json'"
      echo "      - 'npm-shrinkwrap.json'"
Pierre Smeyers's avatar
Pierre Smeyers committed
    else
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
  }

  # this script console output is inserted in generated file: DO NOT ADD LOGS
  function generate_exec_plugin_conf() {
    scriptsConfig=""
Pierre Smeyers's avatar
Pierre Smeyers committed
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_VERIFY_CONDITIONS_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig="${tabs}verifyConditionsCmd: '${scriptPath}'"
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_VERIFY_RELEASE_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig=$(echo -e "${scriptsConfig}\n${tabs}verifyReleaseCmd: '\"${scriptPath}\" \"\${lastRelease.version}\" \"\${nextRelease.version}\" \"\${nextRelease.type}\"'")
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_PREPARE_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig=$(echo -e "${scriptsConfig}\n${tabs}prepareCmd: '\"${scriptPath}\" \"\${lastRelease.version}\" \"\${nextRelease.version}\" \"\${nextRelease.type}\"'")
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_PUBLISH_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig=$(echo -e "${scriptsConfig}\n${tabs}publishCmd: '\"${scriptPath}\" \"\${nextRelease.version}\" \"\${options.branch}\" \"\${commits.length}\" \"\${Date.now()}\"'")
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_SUCCESS_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig=$(echo -e "${scriptsConfig}\n${tabs}successCmd: '\"${scriptPath}\" \"\${lastRelease.version}\" \"\${nextRelease.version}\"'")
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    scriptPath=${SEMREL_HOOKS_DIR}/${SEMREL_FAIL_CMD}
    if [[ -f "${scriptPath}" ]]; then
      chmod +x "${scriptPath}"
      scriptsConfig=$(echo -e "${scriptsConfig}\n${tabs}failCmd: '\"${scriptPath}\" \"\${lastRelease.version}\" \"\${nextRelease.version}\"'")
      tabs="      "
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi
    if [[ -n "${scriptsConfig}" ]]; then
Pierre Smeyers's avatar
Pierre Smeyers committed
      echo "${scriptsConfig}"
    else
      echo ""
    fi
  }

  function install_yd() {
    yd_binary=$1
    yd_version=$2
    yd_url="https://github.com/mikefarah/yq/releases/download/${yd_version}/${yd_binary}.tar.gz"
    wget "${yd_url}" -O - | tar xz && mv "${yd_binary}" /usr/bin/yq
  }

  function dotenv_semrel_info() {
    # removing user conf as we need to override it temporarily (git reset will put things back to normal)
    # see https://www.npmjs.com/package/cosmiconfig for configuration files resolution order (we will use .releaserc)
    releaserc_file="${semrelConfigFile}"
Pierre Smeyers's avatar
Pierre Smeyers committed
    rm -f "package.json"
    yq eval -P 'with_entries(select(.key | . != "plugins"))' "${releaserc_file}" > "${releaserc_file}.new"
Pierre Smeyers's avatar
Pierre Smeyers committed

    # Generating the hook scripts that will generate the dotenv file
    # The dotenv file is generated in $TMPDIR so it will survive the git reset
    dotenv_tmp="$(mktemp -t semrel-info-XXXXXXXXXX.dotenv)"

    export_last_version_hook_script="./export-last-version.sh"
    {
      echo "#!/bin/bash"
      echo "{"
      echo "echo \"SEMREL_INFO_LAST_VERSION=\$1\""
      echo "} > \"${dotenv_tmp}\""
    } > "${export_last_version_hook_script}"
    chmod +x ${export_last_version_hook_script}
    
    export_next_version_hook_script="./export-next-version.sh"
    {
      echo "#!/bin/bash"
      echo "{"
      echo "echo \"SEMREL_INFO_NEXT_VERSION=\$1\""
      echo "echo \"SEMREL_INFO_NEXT_VERSION_TYPE=\$2\""
      echo "} >> \"${dotenv_tmp}\""
    } > "${export_next_version_hook_script}"
    chmod +x ${export_next_version_hook_script}
    
    if [[ -n "$TRACE" ]]; then  
      echo "generated analyzeCommits hook script:"
      cat "${export_last_version_hook_script}"
      echo "generated verifyRelease hook script:"
      cat "${export_next_version_hook_script}"
    fi

    # Generating temporary semantic-release config
    {
      echo ""    
      echo "# injected (replace your plugins) plugins by the template to generate dotenv"    
      echo ""    
Pierre Smeyers's avatar
Pierre Smeyers committed
      echo "plugins: ["
      echo "  \"@semantic-release/commit-analyzer\","
      echo "  ["
      echo "    \"@semantic-release/exec\","
      echo "    {"
      echo "      \"analyzeCommitsCmd\": \"${export_last_version_hook_script} \\\"\${lastRelease.version}\\\"\"",
      echo "      \"verifyReleaseCmd\": \"${export_next_version_hook_script} \\\"\${nextRelease.version}\\\" \\\"\${nextRelease.type}\\\"\""
      echo "    }"
      echo "  ],"
      echo "]"
    } >> "${releaserc_file}.new"
    mv -f "${releaserc_file}.new" ".releaserc"
Pierre Smeyers's avatar
Pierre Smeyers committed

    if [[ -n "$TRACE" ]]; then  
      echo "generated .releaserc:"
      cat ".releaserc"
Pierre Smeyers's avatar
Pierre Smeyers committed
    fi

    npm install -g semantic-release @semantic-release/exec
    semantic-release --dry-run
Pierre Smeyers's avatar
Pierre Smeyers committed

    # Rollback temporary semantic-release configuration
    git reset --hard

    mv "${dotenv_tmp}" "${SEMREL_INFO_FILE}"

    if [[ -n "$TRACE" ]]; then  
      echo "semrel dotenv artifact:"
      cat "${SEMREL_INFO_FILE}"
    fi
  }
  
  function get_latest_template_version() {
Pierre Smeyers's avatar
Pierre Smeyers committed
    tag_json=$(wget -T 5 -q -O - "$CI_API_V4_URL/projects/to-be-continuous%2F$1/repository/tags?per_page=1" 2> /dev/null || curl -s --connect-timeout 5 "$CI_API_V4_URL/projects/to-be-continuous%2F$1/repository/tags?per_page=1" 2> /dev/null || echo "")
Pierre Smeyers's avatar
Pierre Smeyers committed
    echo "$tag_json" | sed -rn 's/^.*"name":"([^"]*)".*$/\1/p'
  }

  function check_for_update() {
    template="$1"
    actual="$2"
    latest=$(get_latest_template_version "$template")
    if [[ -n "$latest" ]] && [[ "$latest" != "$actual" ]]
    then
      log_warn "\\e[1;93m=======================================================================================================\\e[0m"
      log_warn "\\e[93mThe template \\e[32m$template\\e[93m:\\e[33m$actual\\e[93m you're using is not up-to-date: consider upgrading to version \\e[32m$latest\\e[0m"
      log_warn "\\e[93m(set \$TEMPLATE_CHECK_UPDATE_DISABLED to disable this message)\\e[0m"
      log_warn "\\e[1;93m=======================================================================================================\\e[0m"
    fi
  }

  if [[ "$TEMPLATE_CHECK_UPDATE_DISABLED" != "true" ]]; then check_for_update semrel "2.2.5"; fi
  unscope_variables
Pierre Smeyers's avatar
Pierre Smeyers committed
  eval_all_secrets

  # ENDSCRIPT

.semrel-base:
  image: $SEMREL_IMAGE
  services:
Pierre Smeyers's avatar
Pierre Smeyers committed
    - name: "$CI_REGISTRY/to-be-continuous/tools/tracking:master"
      command: ["--service", "semrel", "2.2.5" ]
Pierre Smeyers's avatar
Pierre Smeyers committed
  before_script:
    - *semrel-scripts
    - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"
    - cd "${SEMREL_CONFIG_DIR}"
    - install_yd "yq_linux_amd64" "v4.21.1"
    - prepare_semantic_release
Pierre Smeyers's avatar
Pierre Smeyers committed
  cache:
    # cache shall be per branch per template
    key: "$CI_COMMIT_REF_SLUG-SEMREL"
    paths:
      - .npm/

semantic-release-info:
  extends: .semrel-base
  stage: .pre
  script:
    - dotenv_semrel_info
  artifacts:
    reports:
      dotenv: "${SEMREL_CONFIG_DIR}/$SEMREL_INFO_FILE"
Pierre Smeyers's avatar
Pierre Smeyers committed
  rules:
Cédric OLIVIER's avatar
Cédric OLIVIER committed
    - if: $CI_COMMIT_TAG
      when: never
Pierre Smeyers's avatar
Pierre Smeyers committed
    - if: '$SEMREL_INFO_ON == "prod" && $CI_COMMIT_REF_NAME =~ $PROD_REF'
    - if: '$SEMREL_INFO_ON == "protected" && $CI_COMMIT_REF_PROTECTED == "true"'
    - if: '$SEMREL_INFO_ON == "all"'

semantic-release:
  extends: .semrel-base
  stage: publish
  script:
    - install_semantic_release_plugins
Pierre Smeyers's avatar
Pierre Smeyers committed
    - semantic-release --ci ${SEMREL_DRY_RUN+-d}
Pierre Smeyers's avatar
Pierre Smeyers committed
  rules:
    - if: '$SEMREL_RELEASE_DISABLED == "true"'
Pierre Smeyers's avatar
Pierre Smeyers committed
      when: never
Cédric OLIVIER's avatar
Cédric OLIVIER committed
    - if: $CI_COMMIT_TAG
      when: never      
Pierre Smeyers's avatar
Pierre Smeyers committed
    # on production branch(es): auto if SEMREL_AUTO_RELEASE_ENABLED
    - if: '$SEMREL_AUTO_RELEASE_ENABLED == "true" && $CI_COMMIT_REF_NAME =~ $PROD_REF'
Pierre Smeyers's avatar
Pierre Smeyers committed
    # on production branch(es): manual by default
    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF'
      when: manual