Trying to get a build+push job to only after an approved merge request

I’m trying to make a pipeline that runs as following:

  1. A merge request on a Develop or Staging branch gets approved and merged into said branch
  2. The pipeline builds the Dockerimage
  3. Tags with with :repo_name-branch-merge_request_id
  4. Pushes it to a private DockerHub repo

But I’m having a hard time to make this work as intended. Here’s the gitlab-ci.yml file:

stages:
  - build & push

docker-build:
  # Using the official Docker image for the entire pipeline
  image: docker:latest

  stage: build & push

  services:
    - docker:dind
  
  variables: 
    # Tags with the merge request ID for archive purposes
    tag: ":$CI_PROJECT_TITLE-$CI_MERGE_REQUEST_TARGET_BRANCH_NAME-$CI_MERGE_REQUEST_IID"

  before_script:
    # DockerHub login
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
  script:
    - echo "Building $CI_REGISTRY${tag}"
    - docker build -t "$CI_REGISTRY${tag}" .
    - echo "Pushing $CI_REGISTRY${tag} to DockerHub"
    - docker push "$CI_REGISTRY${tag}"
  rules:
    # Only trigger the job on approved merge requests
    - if: $CI_MERGE_REQUEST_APPROVED && $CI_COMMIT_BRANCH == 'Develop' || 'Staging'
    # Run this job in branches where a Dockerfile exists if above is true
      exists:
        - Dockerfile

What actually happens
Every time someone makes a new branch off ‘Develop’ or ‘Staging’ and commits to that (feature) branch, the pipeline is run in that branch. And whenever you make a merge request in Develop or Staging, it runs a “detached” pipeline before it’s approved. Although that properly tags the image with the variables, I don’t want it to run until the merge request is approved. But the post-merge pipeline that runs afterwards is tagged :repo_name–

I’m new to CI pipelines, is this even the right way to approach this task? I’ve found it surprisingly hard to find any threads about a similar criteria that’s not too dated.
I’m also having issues finding any examples of using $CI_MERGE_REQUEST_APPROVED since it’s relatively new, but seems to be exactly what I want.

Any ideas?

Once the MR is merged it doesn’t exist anymore, all of the CI_MERGE_REQUEST_* variables will be undefined.

One way I can think of achieving your goal would be to get the merge request ID from the merge commit message, something like

id=`git log -1 --pretty=%b | grep 'See merge request' | grep -o '[^!]*$'`
tag=":$CI_PROJECT_TITLE-$CI_COMMIT_BRANCH-$id"

Thanks for the reply!
I figured out that adding only: -merge_requests was a much better solution as it only ran in the merge request, and thus all the merge request variables worked.

Now is the challenge of getting $CI_MERGE_REQUEST_APPROVED to work with this, which I haven’t figured out yet.

As far as I’m aware, approving a MR won’t trigger a new pipeline, so you’d have to approve then manually trigger a new pipeline to get $CI_MERGE_REQUEST_APPROVED to be true.