5

I am currently trying to auto-increment the version, append SNAPSHOT to it and commit to the branch the given tag was created from using GitLab 12.9.2 and GitLab-Shell 12.0.0.

I know, that tags (especially release-tags) are supposed to be created from master, but since I might be getting a develop- or other branches, that I'd like to tag commits on, I wanted to keep the ability to tag a given commit, build, deploy the corresponding artifact (to Nexus), auto-increment the version (e.g. from 0.1.3 to 0.1.4-SNAPSHOT) and commit this to the branch the tag has been created from.

While all other steps work, I fail at the last one, because I cannot find the proper environment variable, which refers to the commit (and branch) the tag was created from.

Here is an excerpt from the CI-file:

build-release:
  extends: .build-template

  only:
    - tags

  before_script:
# Setup git
    - git config http.sslVerify false
    - git config user.email "git-bot@base/gitlab"
    - git config user.name "$GIT_CI_USER"
    - git remote set-url origin https://$GIT_CI_USER:$GIT_CI_PASSWORD@base/gitlab/development/particles/particles-front.git
    - git fetch
#    - git config http.sslCAInfo /etc/gitlab-runner/certs/base.crt ?
#    - git config http.sslCert /etc/gitlab-runner/certs/base.crt ? 

    - cd $CI_BUILDS_DIR/$SUB_PATH
# Install node_modules
    - npm install
# Show versions
    - node --version
    - npm --version
    - npm run ng version
# Save version for artifact-name
    - echo -n $CI_COMMIT_TAG > $CI_BUILDS_DIR/$SUB_PATH/version
# Set version back via npm in order to display it possibly on the user interface
    - npm version $(cat $CI_BUILDS_DIR/$SUB_PATH/version)

  after_script:
# Auto-Increment (patch-)version, append SNAPSHOT, commit & push
    - git checkout $CI_COMMIT_REF_NAME
    - cd $CI_BUILDS_DIR/$SUB_PATH
    - cat $CI_BUILDS_DIR/$SUB_PATH/version
    - npm version patch | cut -c 2-30 | tr -d '\n' > $CI_BUILDS_DIR/$SUB_PATH/version
    - echo -n -SNAPSHOT >> $CI_BUILDS_DIR/$SUB_PATH/version
    - npm version $(cat $CI_BUILDS_DIR/$SUB_PATH/version)
    - npm run prestart
    - git add ./package*.json ./src/_versions.ts
    - git status -sb
    - git commit -m "New Snapshot ($(cat $CI_BUILDS_DIR/$SUB_PATH/version))"
    - git push

The error I am getting (at the last command, as seen in the output console of the job):

$ git push
fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use
    git push origin HEAD:<name-of-remote-branch>

Note: everything works fine except that committing to a $CI_COMMIT_REF_NAME seems to be a bad idea, because it only contains the tag (in the case above), but not the commit (and therefore the branch) the tag was created from. I am talking about this particular value here: New Tag creation dialog in GitLab.

I have read various other topic-related SO questions (such as this one: How do I push to a repo from within a gitlab CI pipeline?), but they don't seem to solve my problem. Another solution using --points-at seems interesting, but I do not know how to use it in a manner, that'd help me solve my problem.

Any help is appreciated!

6 Answers 6

9

A useful trick I like using is to run the printenv Linux command from a pipeline job. This will print all environment variables, including GitLab built-in variables to stdout. Then you can look through these and pick the one you want.

From what I can see, the ones that might help you are the commit SHA or commit message.

Using Commit SHA

  • CI_COMMIT_SHA
  • CI_COMMIT_SHORT_SHA = first 8 digits of CI_COMMIT_SHA

CI_COMMIT_SHA refers to the commit on the branch from which you created the tag. Once you have the commit ID, you can use the GitLab REST API (e.g. using cURL, python requests or python-gitlab) to pull the information you need. Keep in mind that a commit may belong to multiple branches, so you'll need to figure out which one you want to target.

curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/$CI_COMMIT_SHA/refs?type=all"
[
  {"type": "branch", "name": "'test'"},
  {"type": "branch", "name": "add-balsamiq-file"},
  {"type": "branch", "name": "wip"},
  {"type": "tag", "name": "v1.1.0"}
 ]

To learn more about the information you can get from a commit SHA:

Using Commit Message

  • CI_COMMIT_MESSAGE = CI_COMMIT_TITLE + CI_COMMIT_DESCRIPTION
  • CI_COMMIT_TITLE
  • CI_COMMIT_DESCRIPTION

The commit message might help if you follow a specific git process. For example, this is the format of the auto-generated commit messages when a Merge Request auto-squashes commits and merges a feature branch into develop. The tag this message comes from was created from develop:

Merge branch 'feature-branch-name' into 'develop'
Merge request title
See merge request group/project!123

Note: the first line is CI_COMMIT_TITLE, and last 2 lines are CI_COMMIT_DESCRIPTION. CI_COMMIT_TITLE gives you the source branch and target branch, whereas CI_COMMIT_DESCRIPTION gives you the Merge Request title and ID. You can get pretty much all the information you'll need from the MR ID using GitLab REST API.

To learn more about what information you can get from a Merge Request ID:

Unfortunately, if you create a tag from a feature branch, then COMMIT_MESSAGE only gives you the normal commit message written by the user who pushed the commit - probably not very interesting. COMMIT_DESCRIPTION is blank in this case, so also not useful.

3
  • 1
    I actually haven't though of curl-ing my GitLab for the info - thank you! I bet this will be useful! On another note: I seem to have achieved my goal by doing this: CI_SOURCE_BRANCH=$(git for-each-ref | grep $(git show-ref --dereference $CI_COMMIT_TAG -s --abbrev=7 --tags) | grep origin | grep -v $CI_COMMIT_TAG | sed "s/.*\///"); git checkout $CI_SOURCE_BRANCH. It determines the commit-hash from tag and uses git for-each-ref to find it in a branch. Also I exclude the annotated-commit-branch itself (using grep -v). Do you think there might be something wrong with my approach?
    – Igor
    Commented May 27, 2020 at 1:18
  • 1
    @igor No I don't think your approach is wrong. Can you replace $(git show-ref --dereference $CI_COMMIT_TAG -s --abbrev=7 --tags) with $CI_COMMIT_SHA? That would make it more readable. In the end, It comes down to preference. I've been using the GitLab REST API for a long time, so I've just gotten used to it and have developed a number of reusable python/bash scripts. You can do the same with git commands as well. As long as it gets the job done and it covers all your use cases.
    – DV82XL
    Commented May 27, 2020 at 1:57
  • 2
    I actually just did exactly that (moments before reading your most recent comment) and guess what? It worked! Here's the way I determine the source-branch: CI_SOURCE_BRANCH=$(git for-each-ref | grep $CI_COMMIT_SHORT_SHA | grep origin | sed "s/.*\///"). Now my build makes a release, increments the version, appends SNAPSHOT and issues a pipeline for that new SNAPSHOT-version, too! Thank you! Your suggestion to use CI_COMMIT_SHA was awesome (I used CI_COMMIT_SHORT_SHA though, but all the same)! Thanks!
    – Igor
    Commented May 27, 2020 at 1:59
2

A commit tag may be on multiples branches, you can process all branches like this:

deploy:
  - git fetch &> /dev/null
  - CI_COMMIT_BRANCHES=$(git for-each-ref | grep $CI_COMMIT_SHA | grep /remotes/origin/ | sed "s/.*\///")
  - 'echo Tag Branches: $CI_COMMIT_BRANCHES'  
  - >
    for CI_COMMIT_BRANCH in $CI_COMMIT_BRANCHES; do
      echo "Deploy branch $CI_COMMIT_BRANCH"    
    done
1

You can try this:

git branch -a --contains tags/<TAG> | grep origin | sed 's/.*origin\///'
1

Simply do:

$ git branch -r --contains HEAD | sed 's/.*origin\///'
my-release-branch
another-branch

git branch -r --contains HEAD gets all the remote branches the tag belongs to. But the branch names start with origin/ (and some whitespaces)

The sed removes the origin/

0

I also have a similar issue, and end up using a workaround like this :

First, I always set my tag name to include the branch name I'm working / push at. For example : v1.0.0-alpha. From there, I need to get that "alpha" string (the part after the last match of "-" sign) with :

 - BRANCH_NAME=${CI_COMMIT_TAG##*-}

Bonus: if I want to get that semantic version number (1.0.0-alpha) without the "v" part, I use :

 - VERSION_NUMBER=${CI_COMMIT_TAG:1}

Looks ugly but it works.

0

I ended up with this solution, which seemed the most surefire way that worked locally and in the CI runner:

# get tag this pipeline was created from
CURRENT_TAG=$(git describe --tags --abbrev=0)

# describe tag commit to get branch ref - need to exclude tag ref 
LATEST_REF=$(git describe --all --exclude $CURRENT_TAG $CI_COMMIT_HASH)

# optionally filter ref to get only branch name
TAG_BRANCH=${LATEST_REF##*/}

The last part is needed because LATEST_REF will be heads/mybranch or /remotes/origin/myref depending on your environment.

Not the answer you're looking for? Browse other questions tagged or ask your own question.