Same steps for multiple named environments with GitLab CI

Yes, you can use anchors. If I follow the documentation properly, you would rewrite it using a hidden key .XX and then apply it with <<: *X.

For example this to define the key:

.job_template: &deploy_definition
    environment:
         url: ${CI_ENVIRONMENT_SLUG}.mydomain.com
    scripts:
         - deploy ${CI_ENVIRONMENT_SLUG}

And then all blocks can be writen using <<: *job_template. I assume environment will merge the name with the predefined URL.

deploy_to_test:
   <<: *deploy_definition
    environment:
         name: test

deploy_to_stage:
   <<: *deploy_definition
    environment:
         name: stage

 deploy_to_prod:
   <<: *deploy_definition
    environment:
         name: prod

Full docs section from the link above:

YAML has a handy feature called 'anchors', which lets you easily duplicate content across your document. Anchors can be used to duplicate/inherit properties, and is a perfect example to be used with hidden keys to provide templates for your jobs.

The following example uses anchors and map merging. It will create two jobs, test1 and test2, that will inherit the parameters of .job_template, each having their own custom script defined:

.job_template: &job_definition  # Hidden key that defines an anchor named 'job_definition'
  image: ruby:2.1
  services:
    - postgres
    - redis

test1:
  <<: *job_definition           # Merge the contents of the 'job_definition' alias
  script:
    - test1 project

test2:
  <<: *job_definition           # Merge the contents of the 'job_definition' alias
  script:
    - test2 project

& sets up the name of the anchor (job_definition), << means "merge the given hash into the current one", and * includes the named anchor (job_definition again). The expanded version looks like this:

.job_template:
  image: ruby:2.1
  services:
    - postgres
    - redis

test1:
  image: ruby:2.1
  services:
    - postgres
    - redis
  script:
    - test1 project

test2:
  image: ruby:2.1
  services:
    - postgres
    - redis
  script:
    - test2 project

Just in case: Gitlab offers (since 11.3) an extends keyword, which can be used to "templates" yaml entries (so far as I understand it):

See the official doc


Besides what the answer offered, I'd like to add another similar way to achieve kind of the same thing but it's more flexible rather than to use a template and then merge it in a stage.

What you can do is to create a hidden key as well, but in this format, e.g.,

.login: &login |
  cmd1
  cmd2
  cmd3
  ...

And then you can apply it to different stages by using the '*', the asterisk, like:

deploy:
  stage: deploy
  script:
    - ...
    - *login
    - ...

bake:
  stage: bake
  script:
    - ...
    - *login
    - ...

And the result would be equivalent to:

deploy:
  stage: deploy
  script:
    - ...
    - cmd1
    - cmd2
    - cmd3
    - ...

bake:
  stage: bake
  script:
    - ...
    - cmd1
    - cmd2
    - cmd3
    - ...

Based on the resource of: https://gitlab.com/gitlab-org/gitlab-ce/issues/19677#note_13008199

As for the template implementation, it's "merged". With my own experience, if you append more scripts after merging a template, the template scripts will be overwritten. And you cannot apply multiple templates at a time. Only the last template scripts will be executed. For example:

.tmp1: &tmp1
  script:
    - a
    - b

.tmp2: &tmp2
  script:
    - c
    - d

job1:
  <<: *tmp1
  <<: *tmp2
  stage: xxx

job2:
  <<: *tmp2
  stage: yyy
  script:
    - e
    - f

The equivalent result would be:

job1:
  stage: xxx
  script:
    - c
    - d

job2:
  stage: yyy
  script:
    - e
    - f

If not sure about the syntax correctness, just copy and paste your .gitlab.yml file content to "CI Lint" to validate. The button is in the tab of Pipelines.

gitlab gitlab-ci yaml