# Avoid workflow loops on GitHub Actions when committing to a protected branch.

Continuous Deployment (CD) is part of almost every modern application development workflow.  Since the software is deployed using an automated CD workflow, it only makes sense to also auto-increment at least the patch version or build number. 

This can be easily achieved on [`GitHub Actions`](https://docs.github.com/en/actions) with a workflow that will

1. Check out the latest code on the current branch.
2. Increment the patch version or the build number or use any other strategy (like [semantic versioning](https://semver.org/)) to update the current version.
3. Build the application and deploy it to production (or any appropriate environment).
4. Commit changes made to the version to the same branch.

```
name: CD
on:
  push:
    branches:
      - main
jobs:
	deploy:
		name: Deploy to PROD
		runs-on: ubuntu-latest
		steps:
			# Checkout current branch
			- uses: actions/checkout@v2

			# Increment the patch version / build number.
			- name: Bump Version
               run: scripts/bump-build-number.sh

			# Build and deploy app to production.
			- name: Build and Deploy
				run: ...

			# After a successful deployment, commit changes made to the version.
			- name: Commit Version Change
              run: |
					git config user.name "Github Actions CD"
                    git config user.email "<>"
					git add --all
					git commit -m "Bump Version to $NEW_VERSION"
					git push origin main
	

``` 
Here we have a workflow that is triggered by a push on the main branch. In this workflow, we are creating a commit and pushing it to the main branch. 

Since this workflow is triggered on push to the `main` branch and the workflow itself pushed to the `main` branch, we should have ended with a workflow that continuously triggers itself. Why does that not happen?

It is because GitHub Actions generates a [GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret) for each workflow run. This GITHUB_TOKEN is used to set up git on the workflow. Any changes made using that token do not trigger the workflow.

## Committing to Protected Branches

Branches that trigger important workflows like CD usually need to be protected so that we do not end up releasing any unintended changes to the public. We can protect these branches using the [Branch Protection Rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) and add the [Required Pull Request Reviews](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches#require-pull-request-reviews-before-merging) rule.
- Running the above workflow on a protected branch will fail with an error saying that pushing to the protected branch failed.
    ![Screenshot 2022-02-15 at 12.31.10 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645080893890/GQCPlOe5K.png)
    
- To fix this, we can edit the [Branch Protection Rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) to [allow specific users](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule#creating-a-branch-protection-rule) to commit to the protected branch.
    
    ![Screenshot 2022-02-15 at 12.36.19 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645080956522/cYPy9IjN7.png)
    
- Now we can create a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for the user allowed to bypass the rules and save that token to [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository).
    
    ![Screenshot 2022-02-15 at 12.43.17 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645080981991/lrTrpo-qN.png)
    
- Update the CD workflow to use this new token instead of the default `GITHUB_TOKEN`.

```
name: CD
on:
  push:
    branches:
      - main
jobs:
	deploy:
		name: Deploy to PROD
		runs-on: ubuntu-latest
		steps:
			# Checkout current branch
			- uses: actions/checkout@v2
			   with:
                   token: ${{ secrets.PROTECTED_BRANCH_PUSH_TOKEN }}
			...
```
Using the PROTECTED_BRANCH_PUSH_TOKEN allows us to push to a protected branch for the workflow. But since we are no longer using the GITHUB_TOKEN, any commits made to the branch the workflow is triggered on, will re-trigger this workflow. We end up in an infinite loop. 

## Preventing Workflow Loops

Similar to the `GITHUB_TOKEN`, we need a way to stop the re-triggering of the same workflow. 

This is where we can leverage the ability of Github Actions to [skip workflow runs if it detects specific commands in the commit message](https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs).

By adding any of the following commands to our commit message, the workflow triggered on push will not run for that commit.

- `[skip ci]`
- `[ci skip]`
- `[no ci]`
- `[skip actions]`
- `[actions skip]`

We can update the workflow so that the commit message includes one of these commands and we do not end up in an infinite loop.


```
name: CD
on:
  push:
    branches:
      - main
jobs:
	deploy:
		name: Deploy to PROD
		runs-on: ubuntu-latest
		steps:
			# Checkout current branch
			- uses: actions/checkout@v2
				with:
                    token: ${{ secrets.PROTECTED_BRANCH_PUSH_TOKEN }}

			...

			# After successful deployment, commit changes made to version.
			- name: Commit Version Change
               run: |
			        git config user.name "Github Actions CD"
                    git config user.email "<>"
					git add --all
					git commit -m "[skip ci] Bump Version to $NEW_VERSION"
					git push origin main
	

``` 

## In Summary

To push to a protected branch from CD

- Update the [Branch Protection Rule](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) to allow specific users to bypass the protection.
- Create a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)(PAT) for that user with access to the repository.
- Use the PAT in the CD workflow.
- Use commands like `[skip ci]` in the commit message to [skip workflow run](https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs) for that commit.

