Release and Deploy Ansible Collection with GitHub Actions
Published: 2020-08-09 19:20:50

---
title: Release and Deploy Ansible Collection with GitHub Actions
published: true
description: For the next Ansible release, many plugins and modules have migrated to Collections on Ansible Galaxy. The Ansible 2.10 codebase contains a minimal number of modules and plugins and allows other collections to be installed. This post covers how to build and deploy your own collections automatically using GitHub actions.
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/0stsvfh0d3vf2f4millb.jpeg
---

## Prepare your repository

Follow the [Ansible Developer Guide](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections.html) to prepare your content. The published collection can contain plugins, roles and playbooks (TBD) among others. *Please check the oficial documentation regularly to keep your collection up to date*.

## Create your Ansible Galaxy account

Go to [Ansible Galaxy](https://galaxy.ansible.com/) and connect with your GitHub account. In order to publish content automatically to your account, you have to get and copy your personal API key.

1. Click over your username.
2. Preferences.
3. API Key. Show API Key.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z77cvrpdr6hwmhnmiqjr.png)

> **Tip:** For debugging and development purposes, there is a [Development Environment of Ansible Galaxy](https://galaxy-dev.ansible.com) available.

## Adding the API Key to GitHub

1. On GitHub, navigate to the main page of the repository.
2. Under your repository name, click *Settings*.
3. In the left sidebar, click Secrets.
4. Type a name for your secret in the Name input box. We will use `GALAXY_API_KEY` for production and `GALAXYDEV_API_KEY` for development.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rjuxcbefczy9k2dtlud6.png)

Find the full procedure in the [GitHub Documentation](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets).

## Generate your `galaxy.yml` file

The process will read and use the file `galaxy.yml` not only to build the package with the `ansible-galaxy` command, also to create the tag and the release on GitHub. Be sure that the `version` in the file is correct and has not been used before.

At the time of writting, the process doesn't support tag replacement on GitHub or overwrite the version on Galaxy. Although the `replace_old_tag` flag will be available soon for GitHub I recommend to keep control of the releases process. I also recommend the use of the development environment for the first steps.

Example `galaxy.yml`:

```yml
---
namespace: "imjoseangel"
name: "common"
version: "0.1.4"
readme: "README.md"
authors:
    - "Jose Angel Munoz <josea.munoz@gmail.com>"
license:
    - "MIT"
tags:
    - imjoseangel
    - common
    - collection
    - linux
    - windows
    - util
repository: "https://www.github.com/imjoseangel/ansiblecommon"

```

In this example we will create the release `0.1.4` whether in GitHub and Ansible Galaxy.

## Create the GitHub workflow

Create the following structure in your project:

```sh
.github/
└── workflows
    └── release.yml
```

The release.yml contains the actions for GitHub. In our example, we are going to use the action on-demand, using the `workflow_dispatch` option. So the header is:

```yml
---
name: Release and Deploy collection
on: # yamllint disable-line rule:truthy
  workflow_dispatch:
```

We are going to use only one job. The release and the deploy will use exactly the same build and we will avoid different builds for release and deploy.

```yml
jobs:
  releaseanddeploy:
    runs-on: ubuntu-latest
    if: github.repository == 'imjoseangel/ansiblecommon'
    strategy:
      matrix:
        python-version: [3.8]
```

### Steps

First download the branch and read the `version` from the `galaxy.yml` file:

```yml
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Get current version
        id: cversion
        run: echo "::set-output name=version::$(grep version galaxy.yml | awk -F'"' '{ print $2 }')"
```

Use the `python` version defined in the matrix and install `ansible`. Install also the requirements.txt if found. This step is not needed but I think it was cool to keep 😜 as reference.

```yml
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install --upgrade ansible
          if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
```

Create a build directory with the content that will be included in the collection. Note that if you want to add extra files or directories, you need to add those to the `files` or `directories` variables.

```yml
      - name: Copy files and directories to source
        run: |
          mkdir -p build/src
          cp $files build/src
          cp -rf $directories build/src
        env:
          files: "README.md LICENSE ansible.cfg galaxy.yml"
          directories: "inventories playbooks roles vars"
```

Time to build the collection.

```yml
      - name: Build Ansible Collection
        run: ansible-galaxy collection build build/src --force
```

The next two steps will do the following:

1. Creates the release and tag with the version in the `galaxy.yml` file.
2. Adds the instructions to the release.
3. Attachs the collection to the release, keeping the source code (The whole project) and the collection package.

```yml
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: v${{ steps.cversion.outputs.version }}
          release_name: Release v${{ steps.cversion.outputs.version }}
          body: |
            # Ansible Collection: imjoseangel.common
            ![ReleaseBuildCollection](https://github.com/imjoseangel/ansiblecommon/workflows/ReleaseBuildCollection/badge.svg)

            Install with:
            ansible-galaxy collection install -r requirements.yml -f

            The requirements.yml needs to have the following format and content:
            ---
            collections:
                - https://github.com/imjoseangel/ansiblecommon/releases/download/v${{ steps.cversion.outputs.version }}/imjoseangel-common-${{ steps.cversion.outputs.version }}.tar.gz
          draft: false
          prerelease: false

      - name: Upload Release Asset
        id: upload-release-asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: imjoseangel-common-${{ steps.cversion.outputs.version }}.tar.gz
          asset_name: imjoseangel-common-${{ steps.cversion.outputs.version }}.tar.gz
          asset_content_type: application/tar+gzip
```

Finally deploy the package to **Ansible Galaxy**.

```yml
      - name: Deploy Ansible collection to Galaxy
        run: ansible-galaxy collection publish imjoseangel-common-${{ steps.cversion.outputs.version }}.tar.gz --api-key ${{ secrets.GALAXY_API_KEY }}
```

If we want to use the development environment, the `run:` line has to be:

```yml
run: ansible-galaxy collection publish imjoseangel-common-${{ steps.cversion.outputs.version }}.tar.gz --server https://galaxy-dev.ansible.com/ --api-key ${{ secrets.GALAXYDEV_API_KEY }}
```

## Where to find the release

**On GitHub**, under your project releases:

In the example: `https://github.com/imjoseangel/ansiblecommon/releases`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wdskcucoxqzskmbf0kea.png)

**On Ansible Galaxy**, under *My Content*

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/61xe86kg4ripsymhq3i3.png)

## How to install the collection

The easiest way to install the collection is copying the `ansible-galaxy` command from the [Ansible Galaxy](https://galaxy.ansible.com/) project:

`ansible-galaxy collection install imjoseangel.common`

For internal projects, the best way is creating a `requirements.yml` file and follow the instructions in the release document:

```yaml
---
collections:
    - https://github.com/imjoseangel/ansiblecommon/releases/download/v0.1.4/imjoseangel-common-0.1.4.tar.gz
```

Install it with:

```bash
ansible-galaxy collection install -r requirements.yml -f
```

If you want to improve this process or understand it better, you can visit the original project on [**GitHub**](https://github.com/imjoseangel/ansiblecommon)