即使在合并请求获得批准后,Gitlab 管道也会启动

时间:2021-01-29 20:21:49

标签: gitlab

我在 gitlab 中创建了一个项目,并且在 gitlab.yaml 文件中有以下条目。在我推送项目中的任何更改后,管道会启动。是否可以更改此设置,以便管道仅在用户提交合并请求并获得批准后才统计?

这是我的 .gitlab-ci.yaml 文件:

stages:
  - Test
  - Staging
  - Prod

Test:
    stage: Test
    tags:
    - test
    script:
    - cd app_directory
    - cd Test
    - git checkout
    - git pull
    except:
    - master
    when: always
    only:
    - Test  
    only:
    - merge_requests
    allow_failure: false    
Staging:
    stage: Staging
    tags:
    - staging
    script:
    script:
    - cd app_directory
    - cd Staging
    - git checkout
    - git pull
    except:
    - master
    when: always
    only:
    - Test  
    only:
    - merge_requests
    allow_failure: false    
Prod:
    stage: Prod
    tags:
    - Prod
    script:
    - cd app_directory
    - cd Prod
    - git checkout
    - git pull
    except:
    - master
    when: always
    only:
    - Test  
    only:
    - merge_requests
    allow_failure: false    
variables:
    GIT_STRATEGY: clone

1 个答案:

答案 0 :(得分:1)

有一种方法可以仅在合并请求获得批准时运行一个(或多个)作业,但由于您必须与 Approvals API 进行交互,因此更加复杂。但是,只有在 gitlab.com 或自托管 Gitlab 实例上的付费客户才能访问 Approvals API。

Approvals API 具有获取合并请求的批准状态的操作(文档位于此处:https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-the-approval-state-of-merge-requests)。您可以使用以下命令调用它:curl --header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/:project_id:/merge_requests/:merge_request_id:/approval_state" 其中 $PRIVATE_TOKEN 是至少具有 api 范围的个人访问令牌。

:project_id 字段是您项目的 ID,您可以从 Gitlab CI 提供的所有作业的预定义变量之一中获取该 ID:$CI_PROJECT_ID:merge_request_id: 是管道的特定合并请求的 ID(如果有):$CI_MERGE_REQUEST_IID。有了这两个变量,curl 命令现在是:curl --header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/approval_state". Note: there are two predefined variables for merge request ID's. One is $CI_MERGE_REQUEST_ID, which is the gitlab-instance-wide ID, and the other is $CI_MERGE_REQUEST_IID`,它是项目特定的 ID。对于此操作,我们需要项目特定的 IID 变量。

“获取批准状态”操作的结果包含所需批准人数量(如果适用)、符合条件的批准人以及迄今为止已批准的人等信息。它看起来像这样:

{
  "approval_rules_overwritten": true,
  "rules": [
    {
      "id": 1,
      "name": "Ruby",
      "rule_type": "regular",
      "eligible_approvers": [
        {
          "id": 4,
          "name": "John Doe",
          "username": "jdoe",
          "state": "active",
          "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
          "web_url": "http://localhost/jdoe"
        }
      ],
      "approvals_required": 2,
      "users": [
        {
          "id": 4,
          "name": "John Doe",
          "username": "jdoe",
          "state": "active",
          "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
          "web_url": "http://localhost/jdoe"
        }
      ],
      "groups": [],
      "contains_hidden_groups": false,
      "approved_by": [
        {
          "id": 4,
          "name": "John Doe",
          "username": "jdoe",
          "state": "active",
          "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
          "web_url": "http://localhost/jdoe"
        }
      ],
      "source_rule": null,
      "approved": true,
      "overridden": false
    }
  ]
}

获得结果后,您必须对其进行解析,以便您可以使用该信息来确定将运行或不运行哪些作业。 jq 是一个不错的选择。首先,将 Approvals API 的输出保存到文件中,然后我们可以使用 jq。如果为您的合并请求启用了所需的批准,您可以使用 cat output | jq '.["rules"][]["approvals_required"]' 获取所需的编号。要获得批准合并请求的人数,我们可以解析该文件:cat output | jq '.["rules"][]["approved_by"] | length' 您可以在 manual 中阅读有关 jq 的更多信息。

获得这些值后,您就可以决定何时将合并请求视为“已批准”。也许您需要获得所有必需的批准,或者只需要一个批准者,或者获得特定人员的批准。

根据您只想为已批准的合并请求运行的作业数量,您可以在作业本身中运行所有这些,但如果您有许多作业除非获得批准否则不应运行,这可能会令人沮丧投入到每一份工作中。幸运的是,还有另一个 Gitlab CI 功能可以帮助我们。从 Gitlab 12.9 版开始,您可以将文件作为 artifact 上传,它会将内容视为管道中后续阶段的环境变量。

例如,让我们添加一个在管道中的所有其他作业之前运行的作业以命中 Approvals API,使用 jq 解析输出,并决定我们的作业是否应该运行。

stages:
  - check_approvals
  ...

Check Merge Request Approvals:
  stage: check_approvals
  when:never
  rules:
    - if: "$CI_PIPELINE_SOURCE == 'merge_request_event'"
      when: always
  script:
    - curl --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/approval_state > approvals_output
    - REQUIRED_APPROVALS = $(cat approvals_output | jq '.["rules"][]["approvals_required"]')
    - APPROVALS_COUNT = $(cat approvals_output | jq '.["rules"][]["approved_by"] | length')
    - RUN_PIPELINE=false; if ["$APPROVALS_COUNT" -ge "$REQUIRED_APPROVALS"] then
        RUN_PIPELINE=true
      fi
    - echo "RUN_PIPELINE=${RUN_PIPELINE}" >> variables
  artifacts:
    reports:
      dotenv: variables

dotenv 报告类型让我们可以在一个作业阶段定义变量,并在所有后续阶段共享它们。通过将此作业放在第一阶段,管道中的所有其他阶段都可以访问 $RUN_PIPELINE 变量。对于上面的示例,在从 API 获取批准值后,我们将批准数量与所需数量进行比较。如果批准数大于或等于所需的批准数,我们将变量设置为 true。否则就是假的。

默认情况下,我们将此作业设置为从不运行,然后检查 $CI_PIPELINE_SOURCE 变量(包含启动管道的事件)是否为 merge_request_event。如果是,我们运行作业。这确保将设置 $CI_MERGE_REQUEST_IID 变量。

现在,在所有其他只有在合并请求获得批准的情况下才能运行的作业中,我们可以检查变量的值:

Deploy to Prod:
  stage: deploy
  when: never
  rules:
    - if: "$CI_PIPELINE_SOURCE == 'merge_request_event' && $RUN_PIPELINE"
      when: always
  script:
    - ...

首先我们再次检查管道源,因为如果 $RUN_PIPELINE 变量不存在,则它不存在,然后我们检查 $RUN_PIPELINE 是否为真。如果是,我们运行作业,否则默认为从不运行。

资源:

Merge Request Approvals API

Predefined Variables

The rules keyword

The when keyword

The dotenv Report Type

The jq manual