7

In my project I use merge requests to test builds, and deploy once the commit is merged to master. Currently my .gitlab-ci.yml looks like:

build:
  stage: build
  script:
    - yarn build
  artifacts:
    paths:
      - public

deploy:
  stage: deploy
  script: yarn deploy
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

This way only commits that build succesfully get merged to master and deployed. However the build stage runs twice, once in the merge request branch and once in master. I would like to have something like:

build:
  stage: build
  script:
    - yarn build
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

deploy:
  stage: deploy
  script: yarn deploy
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

but the deploy job should have a way to pull the artifact generated by the build job in the merge request branch. Is it possible?

3 Answers3

0

Check if the CI_MERGE_REQUEST_REF_PATH variable is available.

If so, then perhaps you can use that with the GET /projects/:id/jobs/artifacts/:ref_name/download?job=name API call to download the artifact for the job you want in the most recent successful pipeline for the merge request.

Something like this:

rules:
  - if: ${CI_PIPELINE_SOURCE} == "merge_request_event"
script:
    # Download the binaries from the most recent successful pipeline for the CI_MERGE_REQUEST_REF_PATH
    # See: https://docs.gitlab.com/ee/api/job_artifacts.html#download-the-artifacts-archive
    - echo Downloading ${CI_API_V4_URL}/projects/$(echo ${CI_PROJECT_PATH} | sed "s/\//%2F/g")/jobs/artifacts/$(echo ${CI_MERGE_REQUEST_REF_PATH} | sed "s/\//%2F/g")/download?job=build
    # Because of the ':' in the header, the whole curl command must be inside single-quotes
    - 'curl
       --header "JOB-TOKEN: ${CI_JOB_TOKEN}"
       --output ${CI_PROJECT_DIR}/artifacts.zip
       ${CI_API_V4_URL}/projects/$(echo ${CI_PROJECT_PATH} | sed "s/\//%2F/g")/jobs/artifacts/$(echo ${CI_MERGE_REQUEST_REF_PATH} | sed "s/\//%2F/g")/download?job=build'
    # extract desired artifacts from the zip file.
    - unzip
       -o
       -d ${CI_BUILDS_DIR}/${CI_PROJECT_NAMESPACE}
       ${CI_PROJECT_DIR}/artifacts.zip
       'directory/subDirectory/*'

Note that both CI_PROJECT_PATH and CI_MERGE_REQUEST_REF_PATH will usually contain / characters. I used sed to change them to the URL-encoded %2F.

Kevin Rak
  • 336
  • 2
  • 14
  • 2
    As far as I've understood, `CI_MERGE_REQUEST_REF_PATH` is only available for merge request pipelines (detached, results and trains), and will not be available on your default branch that you (most likely) deploy to. – Thor Apr 13 '21 at 13:52
0

You can get the jobs artifacts using:

curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<your_project_id>/jobs/artifacts/$CI_COMMIT_REF_NAME/download?job=<your_job_name>"
ostergaard
  • 3,377
  • 2
  • 30
  • 40
0

I think the most reliable method is to use commit SHAs. How you extract the relevant SHA depends on your merge method: merge commit vs fast-forward. I answered the question assuming you're using the default method (merge commit) but it should be fairly straightforward to adapt to FF.

# Parameters
GITLAB_API_ENDPOINT=https://gitlab.example.org/api/v4
ARTIFACT_JOB_NAME=name-of-the-job-that-creates-the-artifacts-here
# Also generate a token to access GitLab API and set it to GITLAB_PRIVATE_TOKEN

PROJECT_API_ENDPOINT=$GITLAB_API_ENDPOINT'/projects/'$CI_PROJECT_ID

# Getting the second parent because git assigns the main branch as first
# and feature branch as second parent for merge commits. For FF the 
# following line should be modified to be equal to CI_COMMIT_SHA but I 
# didn't test it so approach with caution.
BRANCH_SHA=$(git rev-parse HEAD^2)

# Getting the pipeline id for SHA and redundantly making sure it's an MR event
MR_PIPELINE_ID=$(curl -H "PRIVATE-TOKEN: $GITLAB_PRIVATE_TOKEN" $PROJECT_API_ENDPOINT'/pipelines?source=merge_request_event&sha='$BRANCH_SHA | jq -r '.[0].id')

# Extract the job id
ARTIFACT_JOB_ID=$(curl -H "PRIVATE-TOKEN: $GITLAB_PRIVATE_TOKEN" $PROJECT_API_ENDPOINT'/pipelines/'$MR_PIPELINE_ID'/jobs?name='$ARTIFACT_JOB_NAME | jq -r '.[0].id')

# Finally get the artifact
curl -o artifacts.zip -H "PRIVATE-TOKEN: $GITLAB_PRIVATE_TOKEN" $PROJECT_API_ENDPOINT'/jobs/'$ARTIFACT_JOB_ID'/artifacts'
uzongur
  • 21
  • 1