Using ArgoCD Pull Request Generator to review application modifications
Tags: argocd, devops, pullrequest
Published: 2023-04-11 14:29:12

---
title: Using ArgoCD Pull Request Generator to review application modifications
published: true
description: 
tags: argocd, devops, pullrequest
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0n599fqaa0n9pco52fi.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-03-30 15:50 +0000
---

As a developer, when modifications are pushed to a feature branch, you and your team want to test this new feature. If you have the chance to work with a stateless application, you can deploy another instance of the application with modifications from the feature branch.

An interesting feature of [ArgoCD](https://github.com/argoproj/argo-cd) is the [Pull Request Generator](https://argocd-applicationset.readthedocs.io/en/stable/Generators-Pull-Request/). It's a generator for [ApplicationSet](https://argocd-applicationset.readthedocs.io/en/stable/). An ApplicationSet is a template of ArgoCD [Application](https://argo-cd.readthedocs.io/en/stable/operator-manual/application.yaml) associated with a generator. Generator can be a [directory](https://argocd-applicationset.readthedocs.io/en/stable/Generators-Git/#git-generator-directories): an application will be created for every sub-folder. There is also the [Cluster generator](https://argocd-applicationset.readthedocs.io/en/stable/Generators-Cluster/) that deploy the same Application but in every cluster managed by ArgoCD.

The syntax for the Pull Request generator is quite simple:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: myapps
spec:
  generators:
  - pullRequest:
      github:
        owner: camptocamp
        repo: myrepository
        tokenRef:
          secretName: github-token
          key: token
        labels:
        - deploy
  template:
    ...
```

Before testing this feature what is expected ?

* A new ArgoCD Application is created when a pull request is created with a "deploy" label
* In the template of the Application we can use metadata of the pull request: ID, title, description, labels, source and target branch name, commit ref, …
* A comment is added to the PR when the Application is deployed and Synced with the available URLs

Now we will see how to implement this ;-)

# Workflow before Implementation
## Source Code Repository
Let's start with a simple application repository: `git@github.com:camptocamp/frontend.git`
Let's consider that this repository has a github action that builds a container image when a pull request is opened. The image is tagged with the short commit hash and the concatenation of the branch name and the short commit hash. For example, if the feature branch is name `update_lib` with the last commit: `4a9b29e`, the following tags will be generated: 

* `4a9b29e`
* `update_lib-4a9b29e`

## Deployment Repository
There is another git repository: `git@github.com:camptocamp/argocd-project-foo-apps.git` to describe what needs to be deployed in each kubernetes cluster (dev, int, …). In this repository, we have one folder per environment:

```
apps
├── dev
│   ├── backend
│   └── frontend
├── int
│   ├── backend
│   └── frontend
└── prod
    ├── backend
    └── frontend
```

We are using an ApplicationSet to deploy every component defined in this git repository using the directory generator. For example, for "dev" env:

```yaml
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: foo-dev
  namespace: argocd
spec:
  generators:
  - git:
      directories:
      - path: apps/dev/*
      repoURL: git@github.com:camptocamp/argocd-project-foo-apps.git
      revision: main
  template:
    metadata:
      name: foo-dev-{{path.basename}} # sub folder name
    spec:
      source:
        path: '{{path}}' # full path
        repoURL: git@github.com:camptocamp/argocd-project-foo-apps.git
        targetRevision: main
      project: default
      destination:
        namespace: foo-dev
        server: https://kubernetes.default.svc

```

This ApplicationSet will create one ArgoCD Application per folder in `apps/dev/`. Imagine that we have the following structure in git : 


```
apps
└── dev
    ├── backend
    │   ├── Chart.yaml
    │   └── values.yaml
    ├── database
    │   ├── Chart.yaml
    │   └── values.yaml
    └── frontend
        ├── Chart.yaml
        └── values.yaml
```

This will generate 3 Argocd Applications : 

* foo-dev-database
* foo-dev-backend
* foo-dev-frontend

# Review App Workflow
When a pull request is opened for a specific application, for example the frontend, we want to deploy a new instance of this specific component. We will monitor pull requests on the frontend repository.
So we want to create an additional ApplicationSet to deploy the frontend if a pull request is created with the label `deploy` in the frontend git repository.


# Implementation

## Create a token to access GitHub API
First step is to [create a token](https://github.com/settings/tokens) to access the frontend repository.



Then we need to deploy this token as a kubernetes secret in the cluster : 

```bash
export GITHUB_TOKEN=ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
kubectl create secret generic github-token \
  --from-literal=token=$GITHUB_TOKEN \
  -o yaml --dry-run=client > github-token-secret.yaml
```

If you follow the GitOps principles to deploy manifests in the cluster, you can commit this file.

## Create a webhook
For a better user experience, we can [setup a webhook](https://github.com/Vampouille/demo-argocd-review-app/settings/hooks) that will notify ArgoCD when something changes on Github.
This webhook needs to be defined in the source code repository, where pull requests are created.
Go to the repository "Settings" and then "Webhooks". Click on the "Add webhook" button.
* The Payload URL is the URL to access ArgoCD with the path `/api/webhook`.
* The Content Type should be set to `application/json`.
* It's a good idea to set a "Secret", just use a random string, we will use this random string in the next step.
* Regarding events, we need to individually selects events and choose "Pull requests" events.

## Deploy the new ApplicationSet
This new ApplicationSet will use the "Pull request" generator, this "generator" will monitor pull requests on the source code repository. Just create and commit a file with the following ApplicationSet manifest and deploy this new manifest.

 ```yaml
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: foo-dev-review-frontend
  namespace: argocd
spec:
  generators:
  - pullRequest:
      github:
        owner: camptocamp
        repo: frontend # This is the application source code repo
        tokenRef:
          secretName: github-token
          key: token
        labels:
        - deploy # label on PR that trigger review app
  template:
    metadata:
      name: 'foo-dev-frontend-{{branch}}-{{number}}'
    spec:
      source:
        repoURL: git@github.com:camptocamp/argocd-project-foo-apps.git
        targetRevision: main
        path: apps/dev/frontend
        helm:
          parameters:
          - name: "image.tag"
            value: "{{branch}}-{{head_sha}}" # override of the image tag
          - name: "ingress.prefix"
            value: "{{branch}}" # add a prefix to the URL 
      project: default
      destination:
        server: https://kubernetes.default.svc
        namespace: foo-dev
```

This ApplicationSet will deploy a new instance of the frontend for each pull request with the `deploy` label. The image tag will be overridden with the branch name and the short commit hash and a unique prefix will be added to the URL to avoid conflicts with other instances. Finally, the name of the release is also unique as it's the same as the Application name: `foo-dev-frontend-{{branch}}-{{number}}`, this should also avoid conflicts on object names.

## Configure ArgoCD to use secret for webhook
The last step is to protect the ArgoCD webhook with a password. The ArgoCD Helm chart allows setting a secret for the github webhook endpoint : `configs.secret.githubSecret`.

## Testing

Now it's time to test. For this step, you just need to make a modification in the source repository and create a pull request for this. Please wait until the container image is built. Then by adding the `deploy` label a new ArgoCD app should be created :-)

# Conclusion

This new ArgoCD feature is very interesting. Maybe it can help to have feedback on the pull requests to see the status of the review app. It can also be interesting to have the list of URLs available. ArgoCD already shows this information in the webUI. So maybe just a link to the ArgocD application is enough.

Camptocamp will participate in the KubeCon at Amsterdam from 18 to 21 april. Maybe we can meet there and discuss development workflows that really help developers.