Pull Request Generator

Pull Request Generator

SCMaaS provider(GitHub, Gitea, Bitbucket Server 등)의 API를 사용해 리포지토리 내 열린 pull request를 자동으로 발견하는 generator예요. pull request를 만들 때 테스트 환경을 구축하는 스타일과 잘 맞아요.

출처: 문서

본문

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      # When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes.
      requeueAfterSeconds: 1800
      # See below for provider specific options.
      github:
        # ...

[!NOTE] ApplicationSet에서 PR generator의 보안 영향을 알아두세요. 시크릿 유출을 피하려면 관리자만 ApplicationSet을 생성할 수 있고, PR generator가 있는 ApplicationSet의 project 필드가 템플릿화되어 있다면 경계 밖 리소스 관리가 부여되는 것을 피하려면 관리자만 PR을 생성할 수 있어요.

GitHub

GitHub Pull request를 가져올 리포지토리를 지정하세요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      github:
        # The GitHub organization or user.
        owner: myorg
        # The Github repository
        repo: myrepository
        # For GitHub Enterprise (optional)
        api: https://git.example.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: github-token
          key: token
        # (optional) use a GitHub App to access the API instead of a PAT.
        appSecretName: github-app-repo-creds
        # Labels is used to filter the PRs that you want to target. (optional)
        labels:
        - preview
      requeueAfterSeconds: 1800
  template:
  # ...
  • owner: GitHub 조직 또는 사용자의 필수 이름.
  • repo: GitHub 리포지토리의 필수 이름.
  • api: GitHub Enterprise를 사용한다면, 접근할 URL. (선택)
  • tokenRef: 요청에 사용할 GitHub 접근 토큰을 담고 있는 Secret 이름과 키. 지정하지 않으면 익명 요청을 하며, 이는 더 낮은 rate limit을 갖고 공개 리포지토리만 볼 수 있어요. (선택)
  • labels: 나열된 라벨을 모두 포함하는 PR로 필터링. (선택)
  • appSecretName: repo-creds 형식의 GitHub App 시크릿을 담고 있는 Secret 이름.

GitLab

GitLab merge request를 가져올 프로젝트를 지정하세요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      gitlab:
        # The GitLab project ID.
        project: "12341234"
        # For self-hosted GitLab (optional)
        api: https://git.example.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitlab-token
          key: token
        # Labels is used to filter the MRs that you want to target. (optional)
        labels:
        - preview
        # MR state is used to filter MRs only with a certain state. (optional)
        pullRequestState: opened
        # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates.
        insecure: false
        # Reference to a ConfigMap containing trusted CA certs - useful for self-signed certificates. (optional)
        caRef:
          configMapName: argocd-tls-certs-cm
          key: gitlab-ca
      requeueAfterSeconds: 1800
  template:
  # ...
  • project: GitLab 프로젝트의 필수 프로젝트 ID.
  • api: 자체 호스팅 GitLab을 사용한다면, 접근할 URL. (선택)
  • tokenRef: 요청에 사용할 GitLab 접근 토큰을 담고 있는 Secret 이름과 키. 지정하지 않으면 익명 요청을 하며, 이는 더 낮은 rate limit을 갖고 공개 리포지토리만 볼 수 있어요. (선택)
  • labels: 타겟팅하려는 MR을 필터링하는 데 사용되는 라벨. (선택)
  • pullRequestState: 특정 상태의 MR만 가져오는 추가 MR 필터. 기본적으로 모든 상태. 기본값: "" (모든 상태). 유효한 값: "", opened, closed, merged 또는 locked. (선택)
  • insecure: 기본값(false) - SCM 인증서 유효성 확인 건너뜀 - 자체 서명 TLS 인증서에 유용.
  • caRef: 신뢰할 GitLab 인증서를 담고 있는 선택적 ConfigMap 이름과 키 - 자체 서명 TLS 인증서에 유용. 신뢰할 인증서를 보유한 ArgoCD CM을 참조할 수 있음.

insecure를 true로 설정하는 것보다 선호할 만한 대안으로 applicationset 컨트롤러에 자체 서명 인증서를 마운트해 Gitlab용 자체 서명 TLS 인증서를 구성할 수 있어요.

Gitea

Gitea Pull request를 가져올 리포지토리를 지정하세요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      gitea:
        # The Gitea organization or user.
        owner: myorg
        # The Gitea repository
        repo: myrepository
        # The Gitea url to use
        api: https://gitea.mydomain.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: gitea-token
          key: token
        # many gitea deployments use TLS, but many are self-hosted and self-signed certificates
        insecure: true
      requeueAfterSeconds: 1800
  template:
  # ...
  • owner: Gitea 조직 또는 사용자의 필수 이름.
  • repo: Gitea 리포지토리의 필수 이름.
  • api: Gitea 인스턴스의 url.
  • tokenRef: 요청에 사용할 Gitea 접근 토큰을 담고 있는 Secret 이름과 키. 지정하지 않으면 익명 요청을 하며, 이는 더 낮은 rate limit을 갖고 공개 리포지토리만 볼 수 있어요. (선택)
  • insecure: 자체 서명 인증서 허용, 주로 테스트용.

Bitbucket Server

Bitbucket Server(Bitbucket Cloud와 다름)에 호스팅된 repo에서 pull request를 가져와요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      bitbucketServer:
        project: myproject
        repo: myrepository
        # URL of the Bitbucket Server. Required.
        api: https://mycompany.bitbucket.org
        # Credentials for Basic authentication (App Password). Either basicAuth or bearerToken
        # authentication is required to access private repositories
        basicAuth:
          # The username to authenticate with
          username: myuser
          # Reference to a Secret containing the password or personal access token.
          passwordRef:
            secretName: mypassword
            key: password
        # Credentials for Bearer Token (App Token) authentication. Either basicAuth or bearerToken
        # authentication is required to access private repositories
        bearerToken:
          # Reference to a Secret containing the bearer token.
          tokenRef:
            secretName: repotoken
            key: token
        # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates.
        insecure: true
        # Reference to a ConfigMap containing trusted CA certs - useful for self-signed certificates. (optional)
        caRef:
          configMapName: argocd-tls-certs-cm
          key: bitbucket-ca
      # Labels are not supported by Bitbucket Server, so filtering by label is not possible.
      # Filter PRs using the source branch name. (optional)
      filters:
      - branchMatch: ".*-argocd"
  template:
  # ...
  • project: Bitbucket 프로젝트의 필수 이름
  • repo: Bitbucket 리포지토리의 필수 이름.
  • api: Bitbucket REST API에 접근하는 필수 URL. 위 예시의 경우 https://mycompany.bitbucket.org/rest/api/1.0/projects/myproject/repos/myrepository/pull-requests로 API 요청이 이루어져요.
  • branchMatch: 소스 브랜치 이름과 일치해야 하는 선택적 regexp 필터. Bitbucket server가 지원하지 않는 라벨의 대안이에요.

개인 리포지토리에 접근하려면 Basic auth 자격 증명도 제공해야 해요(현재 지원되는 유일한 인증): * username: 인증에 사용할 사용자 이름. 관련 repo에 대한 읽기 접근만 필요해요. * passwordRef: 요청에 사용할 비밀번호 또는 개인 접근 토큰을 담고 있는 Secret 이름과 키.

Bitbucket App Token의 경우 bearerToken 섹션을 사용하세요. * tokenRef: 요청에 사용할 app token을 담고 있는 Secret 이름과 키.

자체 서명 BitBucket Server 인증서의 경우 다음 옵션이 유용할 수 있어요: * insecure: 기본값(false) - SCM 인증서 유효성 확인 건너뜀 - 자체 서명 TLS 인증서에 유용. * caRef: 신뢰할 BitBucket 서버 인증서를 담고 있는 선택적 ConfigMap 이름과 키 - 자체 서명 TLS 인증서에 유용. 신뢰할 인증서를 보유한 ArgoCD CM을 참조할 수 있음.

Bitbucket Cloud

Bitbucket Cloud에 호스팅된 repo에서 pull request를 가져와요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
    - pullRequest:
        bitbucket:
          # Workspace name where the repository is stored under. Required.
          owner: myproject
          # Repository slug. Required.
          repo: myrepository
          # URL of the Bitbucket Server. (optional) Will default to 'https://api.bitbucket.org/2.0'.
          api: https://api.bitbucket.org/2.0
          # Credentials for Basic authentication (App Password). Either basicAuth or bearerToken
          # authentication is required to access private repositories
          basicAuth:
            # The username to authenticate with
            username: myuser
            # Reference to a Secret containing the password or personal access token.
            passwordRef:
              secretName: mypassword
              key: password
          # Credentials for Bearer Token (App Token) authentication. Either basicAuth or bearerToken
          # authentication is required to access private repositories
          bearerToken:
            # Reference to a Secret containing the bearer token.
            tokenRef:
              secretName: repotoken
              key: token
        # Labels are not supported by Bitbucket Cloud, so filtering by label is not possible.
        # Filter PRs using the source branch name. (optional)
        filters:
          - branchMatch: ".*-argocd"

          # If you need to filter destination branch too, you can use this
          - targetBranchMatch: "master"

          # Also you can combine source and target branch filters like
          # This case will match any pull-request where source branch ends with "-argocd" and destination branch is master
          - branchMatch: ".*-argocd"
            targetBranchMatch: "master"
  template:
  # ...
  • owner: Bitbucket 워크스페이스의 필수 이름
  • repo: Bitbucket 리포지토리의 필수 이름.
  • api: Bitbucket REST API에 접근하는 선택적 URL. 위 예시의 경우 https://api.bitbucket.org/2.0/repositories/{workspace}/{repo_slug}/pullrequests로 API 요청이 이루어져요. 설정하지 않으면 기본값 https://api.bitbucket.org/2.0

브랜치 filters를 사용할 수 있어요: - branchMatch: 소스 브랜치 이름과 일치해야 하는 선택적 regexp 필터. - targetBranchMatch: 대상 브랜치 이름과 일치해야 하는 선택적 regexp 필터.

[!NOTE] 라벨은 Bitbucket에서 지원되지 않아요.

개인 리포지토리에 접근하려면 Argo CD가 Bitbucket Cloud의 리포지토리에 접근할 자격 증명이 필요해요. Bitbucket App Password(사용자별로 생성, 전체 워크스페이스에 접근) 또는 Bitbucket App Token(리포지토리별로 생성, 리포지토리 범위로만 접근 제한)을 사용할 수 있어요. App Password와 App Token이 모두 정의되면 App Token이 사용돼요.

Bitbucket App Password를 사용하려면 basicAuth 섹션을 사용하세요. - username: 인증에 사용할 사용자 이름. 관련 repo에 대한 읽기 접근만 필요해요. - passwordRef: 요청에 사용할 비밀번호 또는 개인 접근 토큰을 담고 있는 Secret 이름과 키.

Bitbucket App Token의 경우 bearerToken 섹션을 사용하세요. - tokenRef: 요청에 사용할 app token을 담고 있는 Secret 이름과 키.

Azure DevOps

pull request를 가져올 조직, 프로젝트, 리포지토리를 지정하세요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      azuredevops:
        # Azure DevOps org to scan. Required.
        organization: myorg
        # Azure DevOps project name to scan. Required.
        project: myproject
        # Azure DevOps repo name to scan. Required.
        repo: myrepository
        # The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/.
        api: https://dev.azure.com/
        # Reference to a Secret containing an access token. (optional)
        tokenRef:
          secretName: azure-devops-token
          key: token
        # Labels is used to filter the PRs that you want to target. (optional)
        labels:
        - preview
      requeueAfterSeconds: 1800
  template:
  # ...
  • organization: Azure DevOps 조직의 필수 이름.
  • project: Azure DevOps 프로젝트의 필수 이름.
  • repo: Azure DevOps 리포지토리의 필수 이름.
  • api: 자체 호스팅 Azure DevOps Repos를 사용한다면, 접근할 URL. (선택)
  • tokenRef: 요청에 사용할 Azure DevOps 접근 토큰을 담고 있는 Secret 이름과 키. 지정하지 않으면 익명 요청을 하며, 이는 더 낮은 rate limit을 갖고 공개 리포지토리만 볼 수 있어요. (선택)
  • labels: 나열된 라벨을 모두 포함하는 PR로 필터링. (선택)

필터 (Filters)

필터는 어떤 pull request를 생성 대상으로 선택할지 선택할 수 있게 해줘요. 각 필터는 하나 이상의 조건을 선언할 수 있으며, 모두 통과해야 해요. 여러 필터가 있으면 그중 하나라도 매치되면 리포지토리가 포함돼요. 필터가 지정되지 않으면 모든 pull request가 처리돼요. 현재는 SCM provider 필터와 비교할 때 필터의 하위 집합만 사용할 수 있어요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      # ...
      # Include any pull request branch ending with "argocd"
      # and pull request title starting with "feat:". (optional)
      filters:
      - branchMatch: ".*-argocd"
      - titleMatch: "^feat:"
  template:
  # ...
  • branchMatch: 소스 브랜치 이름과 매칭되는 regexp.
  • targetBranchMatch: 대상 브랜치 이름과 매칭되는 regexp.
  • titleMatch: Pull Request 제목과 매칭되는 regexp.

GitHub와 GitLab은 labels 필터도 지원해요.

템플릿 (Template)

다른 모든 generator와 마찬가지로 생성된 애플리케이션에서 대체할 여러 키가 사용 가능해요.

다음은 포괄적인 Helm Application 예시예요:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
    # ...
  template:
    metadata:
      name: 'myapp-{{.branch}}-{{.number}}'
    spec:
      source:
        repoURL: 'https://github.com/myorg/myrepo.git'
        targetRevision: '{{.head_sha}}'
        path: kubernetes/
        helm:
          parameters:
          - name: "image.tag"
            value: "pull-{{.author}}-{{.head_sha}}"
      project: "my-project"
      destination:
        server: https://kubernetes.default.svc
        namespace: default

그리고 여기 견고한 Kustomize 예시가 있어요:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
    # ...
  template:
    metadata:
      name: 'myapp-{{.branch}}-{{.number}}'
    spec:
      source:
        repoURL: 'https://github.com/myorg/myrepo.git'
        targetRevision: '{{.head_sha}}'
        path: kubernetes/
        kustomize:
          nameSuffix: '{{.branch}}'
          commonLabels:
            app.kubernetes.io/instance: '{{.branch}}-{{.number}}'
          images:
          - 'ghcr.io/myorg/myrepo:{{.author}}-{{.head_sha}}'
      project: "my-project"
      destination:
        server: https://kubernetes.default.svc
        namespace: default
  • number: pull request의 ID 번호.
  • title: pull request의 제목.
  • branch: pull request head 브랜치의 이름.
  • branch_slug: 브랜치 이름을 RFC 1123에 정의된 DNS 라벨 표준에 맞게 정리하고, 13자를 더 붙일 여유를 주기 위해 50자로 자른 값.
  • target_branch: pull request 대상 브랜치의 이름.
  • target_branch_slug: 대상 브랜치 이름을 RFC 1123에 정의된 DNS 라벨 표준에 맞게 정리하고, 13자를 더 붙일 여유를 주기 위해 50자로 자른 값.
  • head_sha: pull request head의 SHA.
  • head_short_sha: pull request head의 짧은 SHA(8자 또는 더 짧으면 head SHA의 길이).
  • head_short_sha_7: pull request head의 짧은 SHA(7자 또는 더 짧으면 head SHA의 길이).
  • labels: pull request 라벨 배열. (Go Template ApplicationSet 매니페스트에서만 지원)
  • author: pull request의 작성자/생성자.

웹훅 구성 (Webhook Configuration)

Pull Request generator를 사용할 때 ApplicationSet 컨트롤러는 requeueAfterSeconds 간격(기본 30분)마다 폴링해 변경을 감지해요. 이 폴링 지연을 없애기 위해 ApplicationSet 웹훅 서버가 웹훅 이벤트를 받도록 구성할 수 있으며, 이는 Pull Request generator가 Application 생성을 트리거하게 해요.

구성은 Git generator에서 설명한 것과 거의 같지만, 한 가지 차이가 있어요: Pull Request Generator도 사용하려면 다음 설정을 추가로 구성하세요.

[!NOTE] ApplicationSet 컨트롤러 웹훅은 같은 API server 웹훅을 사용하지 않아요. ApplicationSet은 웹훅 서버를 ClusterIP 유형의 서비스로 노출해요. 이 서비스를 웹훅 소스에 노출하려면 ApplicationSet 전용 Ingress 리소스를 만들어야 해요.

Github 웹훅 구성

1단계 "Git provider에서 웹훅 생성" 에서 pull request가 생성, 닫힘, 또는 라벨 변경 시 웹훅 요청이 보내지도록 이벤트를 추가하세요.

uri /api/webhook로 웹훅 URL을 추가하고 content-type을 json으로 선택하세요.

Let me select individual events를 선택하고 Pull requests 체크박스를 활성화하세요.

Pull Request Generator는 다음 동작이 발생하면 requeue돼요:

  • opened
  • closed
  • reopened
  • labeled
  • unlabeled
  • synchronized

각 이벤트에 대한 자세한 내용은 공식 문서를 참고하세요.

Gitlab 웹훅 구성

트리거 목록에서 "Merge request events" 체크박스를 활성화하세요.

Pull Request Generator는 다음 동작이 발생하면 requeue돼요:

  • open
  • close
  • reopen
  • update
  • merge

각 이벤트에 대한 자세한 내용은 공식 문서를 참고하세요.

수명 주기 (Lifecycle)

구성된 기준이 충족될 때 Pull Request가 발견되면 Application이 생성돼요 — 즉 GitHub의 경우 Pull Request가 지정된 labels 및/또는 pullRequestState와 일치할 때요. Pull Request가 더 이상 지정된 기준을 충족하지 않으면 Application이 제거돼요.

values 필드로 추가 key-value 쌍 전달 (Pass additional key-value pairs via values field)

어떤 Pull Request generator든 values 필드로 추가적이고 임의의 문자열 key-value 쌍을 전달할 수 있어요. values 필드로 추가된 값은 values.(field)로 추가돼요.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  goTemplate: true
  goTemplateOptions: ["missingkey=error"]
  generators:
  - pullRequest:
      # ...
      values:
        pr_branch: '{{ .branch }}'
  template:
    metadata:
      name: '{{ .values.name }}'
    spec:
      source:
        repoURL: '{{ .url }}'
        targetRevision: '{{ .branch }}'
        path: kubernetes/
      project: default
      destination:
        server: https://kubernetes.default.svc
        namespace: default

[!NOTE] values. 프리픽스는 항상 generators.pullRequest.values 필드를 통해 제공된 값 앞에 붙어요. template의 파라미터 이름에 이 프리픽스를 포함해야 해요.

values에서는 위에서 언급한 Pull Request generator가 설정한 모든 필드도 보간할 수 있어요.

더 알아보기 (Learn more)