Release keyword does not use variables from script

Summary

The release description can be quite well formatted as part of the tag message. After all, git is a database of sorts, and putting release notes into the release tags seems quite sensible. Further more, we don't want to store the release notes (the description) in the gitlab CI file, as that is a new commit in itself and having release related changes in the CI file is a bit ugly, especially as we have a perfectly good medium for this, annotated git tags.

As we still suffer from bug #22831 (closed) we cannot assign the description the value of '${CI_COMMIT_TAG_MESSAGE}' and thus have to resolve the tag message manually to assign to the description. The following snippet would do just that:

announce_release:
  image: "registry.gitlab.com/gitlab-org/release-cli:latest"
  stage: complete
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+(\.\d+)+$/'
      when: delayed
      start_in: 86 minutes
  script:
    - apk add --no-cache git  # Workaround for gitlab-org/gitlab#237792
    - |
      CI_COMMIT_TAG_MESSAGE="$(git tag \
                                       --format="%(contents:subject)%0a%0a%(contents:body)" \
                                       --list ${CI_COMMIT_TAG:?} | sed 's|\r |\n|g')"
    - |
      if [ -z "${CI_COMMIT_TAG_MESSAGE:-}" ]; then
        CI_COMMIT_TAG_MESSAGE="$(printf "See tag '%s'\n\n(Auto-created release candidate)" "${CI_COMMIT_TAG:?}")"
      fi
    - echo "Release notes ${CI_COMMIT_TAG_MESSAGE}"
  release:
    name: "${CI_PROJECT_NAME} ${CI_COMMIT_TAG}"
    description: "${CI_COMMIT_TAG_MESSAGE:-No release notes.}"
    tag_name: "${CI_COMMIT_TAG}"

The release keyword variables however are expanded before the script has run, even though the success of the job relies on the output of the script and according to the pipeline output runs after the script has run.

"a" solution shown in the README, is to store the description in a dotenv variable. While interesting in principle, the current limitation (no newlines allowed) makes it almost useless.

We could generate the variable in a previous step (where that to exist), store it in a file (artifact) and do a description: "$(cat file.txt)" which is also very ugly, and relies on the fact that this was actually run in a previous step.

The only reasonable work-around is to call the release-cli manually, but that kind of defeats the purpose of the release keyword in the yaml file ...

  script:
    - release-cli create --name "${CI_PROJECT_NAME}" --description "${CI_COMMIT_TAG_MESSAGE:-No release notes.}" --tag-name "${CI_COMMIT_TAG}"

Which works, but is sad to see, as it makes the entire release yaml definition irrelevant.

While this summary uses the variable definition and expansion of CI_COMMIT_TAG_MESSAGE, this can apply to any example equally. e.g.

script:
  - RELEASE_CLI_DESCRIPTION="My release"
after_script:
  export RELEASE_CLI_DESCRIPTION
release:
  description: "${RELEASE_CLI_DESCRIPTION:-Nothing}"

Would unexpectedly still fail. While I'm sure there's technical reasons this can't work (the release command is generated on the rails side, but the script is much later executed on the runner probably) doesn't work for the user. He tries to do something that seems perfectly logical (pipeline job/release fails if script fails), yet it doesn't work.

What is the expected bug behavior?

The description is left empty ...

What is the expected bug behavior?

The description is filled with dynamic data

Output of checks

This bug happens on GitLab.com

Possible fixes

For one, pospone variable expansion for the runner to be picked up. I guess one potential hack would be to escape the first round of dollar signs in the yaml file, so that the first eval delivers it as a whole to the runner's commandline.

  release:
    description: "\${CI_COMMIT_TAG_MESSAGE}"

Sadly, this causes a parser error (found unknown escape character while parsing a quoted scalar at) so even this is needed, it should be invisible to the user ...

Edited by Olliver Schinagl