skip to Main Content

I’m trying to assign values to the list of variables, according of appropriate choice maded at the pipeline startup. So In my case:

I have a gitlab-ci.yml file with following:

variables:
  DOCKER_DRIVER: overlay
  REGISTRY: registry.restream.ru:5000
  CENTOS_TESTS_VERSION: 1.1.3
  CENTOS_PYTHON_VERSION: 1.0.5
  CENTOS_CPP_VERSION: 1.0.4
  REDOS7_CPP_VERSION: 1.0.0
  REDOS8_TESTS_VERSION: 1.0.0
  REDOS8_CPP_VERSION: 1.0.0
  REDOS8_PYTHON_VERSION: 1.0.0
  OS_VERSION:
    value: "RedOS-8"
    options:
      - "RedOS-8"
      - "CentOS-7"
      - "RedOS-7"
    description: "The deployment target. Set to 'RedOS-8' by default."
  COMPONENT_TYPE:
      value: "Python"
      options:
        - "Python"
        - "C++"
        - "Tests"
      description: "The deployment component type. Set to 'Python' by default."

default:
  before_script:
    - >
      if [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "C++" ]]; then
          variables:
            DOCKERFILE = ./redos8/cpp.Dockerfile
            IMAGE_NAME = redos8-cpp
            IMAGE_VERSION = $REDOS8_CPP_VERSION
      elif [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "Python" ]]; then
          variables:
            DOCKERFILE = ./redos8/python.Dockerfile
            IMAGE_NAME: redos8-python
            IMAGE_VERSION = REDOS8_PYTHON_VERSION
      elif [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "Tests" ]]; then
          variables:
            DOCKERFILE: ./redos8/tests.Dockerfile
            IMAGE_NAME: redos8-tests
            IMAGE_VERSION = $REDOS8_TESTS_VERSION
      elif [[ $OS_VERSION = "RedOS-7" ]]; then
          variables:
            DOCKERFILE = ./redos7/cpp.Dockerfile
            IMAGE_NAME = redos7-cpp
            IMAGE_VERSION = $REDOS7_CPP_VERSION
      elif [[ $OS_VERSION = "CentOS-7" ]] && [[ $COMPONENT_TYPE = "Python" ]]; then
          variables:
            DOCKERFILE = ./redos7/python.Dockerfile
            IMAGE_NAME = centos7-python
            IMAGE_VERSION = $CENTOS_PYTHON_VERSION   
      else
          variables:
            DOCKERFILE = ./centos7/cpp.Dockerfile
      fi

stages:
  - lint
  - build

.lint:
  stage: lint
  image: $REGISTRY/hadolint/hadolint:v2.12.0-alpine
  rules:
    - changes:
        - $DOCKERFILE
        - repo/*
        - scripts/*
  tags:
    - dind
  script:
    - hadolint $DOCKERFILE

.build:
  image: $REGISTRY/docker:latest
  services:
    - $REGISTRY/docker:dind
  stage: build
  variables:
    FULL_IMAGE_NAME: $REGISTRY/rtpp-team/ci-cd/$IMAGE_NAME:$IMAGE_VERSION
  rules:
    - changes:
        - $DOCKERFILE
        - repo/*
        - scripts/*
  tags:
    - dind
  script:
      
    - docker build --pull --tag $FULL_IMAGE_NAME --file $DOCKERFILE .
    - docker push $FULL_IMAGE_NAME

lint_dockerfile:tests:
  extends: .lint
  variables:
    DOCKERFILE: $DOCKERFILE

build_image:tests:
  extends: .build
  variables:
    DOCKERFILE: $DOCKERFILE
    IMAGE_NAME: $IMAGE_NAME
    IMAGE_VERSION: $CENTOS_TESTS_VERSION
  needs:
    - job: lint_dockerfile:tests

lint_dockerfile:python:
  extends: .lint
  variables:
    DOCKERFILE: $DOCKERFILE

build_image:python:
  extends: .build
  variables:
    DOCKERFILE: $DOCKERFILE
    IMAGE_NAME: $IMAGE_NAME
    IMAGE_VERSION: $CENTOS_PYTHON_VERSION
  needs:
    - job: lint_dockerfile:python

lint_dockerfile:cpp:
  extends: .lint
  variables:
    DOCKERFILE: $DOCKERFILE

build_image:cpp:
  extends: .build
  variables:
    DOCKERFILE: $DOCKERFILE
    IMAGE_NAME: $IMAGE_VERSION
    IMAGE_VERSION: $CENTOS_CPP_VERSION
  needs:
    - job: lint_dockerfile:cpp

For example, I chose condition like "RedOS-8" + "C++".

In log output I get:

Getting source from Git repository
00:01
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /builds/dev_team/devops/ci-cd-docker-images/.git/
Checking out 61cad3e4 as detached HEAD (ref is devops/WINK-5057)
Skipping Git submodules setup
Executing "step_script" stage of the job script
00:01
Using docker image sha256:19b38dcec411d7f333601a68f55cb3e710fca099615a7eee0fa2e020adfc7292 for registry.team.ru:5000/hadolint/hadolint:v2.12.0-alpine with digest hadolint/hadolint@sha256:3c206a451cec6d486367e758645269fd7d696c5ccb6ff59d8b03b0e45268a199
$ if [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "C++" ]]; then # collapsed multi-line command
/bin/sh: eval: line 179: variables:: not found

I tried to change multi-line characters from > to |. Also, I tried to use one condition for test like:

default:
  before_script:
    - >
      if [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "C++" ]]; then
          variables:
            DOCKERFILE = ./redos8/cpp.Dockerfile
            IMAGE_NAME = redos8-cpp
            IMAGE_VERSION = $REDOS8_CPP_VERSION

With no result. The log output gave me the same error with "# collapsed multi-line command" and $DOCKERFILE not found for the first pipeline step called "hadolint".

2

Answers


  1. You could have a first job that run the conditional logic but writes the environment variables in a file, and then use the content of that file as env vars for next jobs thanks to artifacts:reports:dotenv.

    Generic example:

    build-job:
      stage: build
      script:
        - echo "BUILD_VARIABLE=value_from_build_job" >> build.env
      artifacts:
        reports:
          dotenv: build.env
    
    test-job:
      stage: test
      script:
        - echo "$BUILD_VARIABLE"  # Output is: 'value_from_build_job'
    

    See:

    Login or Signup to reply.
  2. Writing long scripts in the pipline reduces readability and invites errors. Use shellcheck.

    variables: is not a shell command, so you get /bin/sh: eval: line 179: variables:: not found . DOCKERFILE = ./redos8/cpp.Dockerfile is not shell assignment.

    Create a shell script in the repository:

    #!/bin/sh
    # before_script.sh
    case "$OS_VERSION $COMPONENT_TYPE"
    'RedOS-8 C++')
        export DOCKERFILE=./redos8/cpp.Dockerfile
        export IMAGE_NAME=redos8-cpp
        export IMAGE_VERSION=$REDOS8_CPP_VERSION
        ;;
    'RedOS-8 Python')
        # etc..
        ;;
    'RedOS-7 '*)
        # etc..
        ;;
    esac
    
    "$@"
    

    Then source it from the pipeline.

    default:
       before_script:
          - . ./before_script.sh
    

    I also like beeing explicit. The last "$@" can be used to run as a wrapper, which allows for easy local testing:

    script:
       - ./before_script.sh some command with required environment
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search