Using Github Actions to scaffold repositories
Usually, in many projects, we need to create different repositories with a similar folder structure. In this scenario, you can use GitHub Templates, which I will cover in another blog post. For now, in this post, I’d like to discuss how to use GitHub Actions to scaffold monorepo repositories using CookieCutter in a self-service manner.
CookieCutter
CookieCutter is a tool that help us creating templates using Jinja2 as templating language. Some examples are:
apiVersion: v2
name: {{cookiecutter.service}}
description: The helm chart for {{cookiecutter.service}}
type: application
version: 0.1.1
appVersion: 0.1.1
dependencies:
- name: ecs-service-generic
version: ~1
repository: "oci://my-ecr-repo/helm-charts"
In addition, this tool uses an answer file called cookiecutter.json to set up the default values for each variable in the templates. We can take advantage of this file to configure default settings for our environments, such as:
{
"tenant": "tenantName",
"service": "serviceName",
"environments": {
"dev": {
"accountId": "11111",
"vpcId": "11111",
"albSubnets":"11111",
"serviceSubnets":"11111",
"permissionsBoundary": "11111",
"kmsARN": "11111",
"albDns": "11111",
"domain": "11111",
"zoneId": "11111",
"securityGroupECS": "11111",
"certificateArn": "11111"
}
}
}
Later, by running the following command, we can create the template. Please note that we are passing the tenant and service as parameters in the command and using –no-input to avoid prompting for values, relying solely on the responses from the cookiecutter.json file.
cookiecutter -s -f --no-input _template tenant=tenant1 service=myservice1
We are using -f
to overwrite the content if folder exists, it allow us to creates new files if needed, and -s
to skip render files again if already exists to don’t overwrite if the user has made any change.
You can find more information about it in the official documentation.
Github Actions
Now, let’s use GitHub Actions to establish a self-service process, allowing users to automatically create a pull request with their requirements for new tenants or services.
First, let’s create the user input interface, define the parameters, and configure it as a manually triggered pipeline:
name: Create new service or tenant
run-name: $ is creating new service or tenant 🚀
on:
workflow_dispatch: # Manual execution
inputs:
tenant: # Static parameters
description: 'Tenant'
type: choice
options:
- tenant1
- tenant2
- tenant3
- tenant4
required: true
serviceName: # Dynamic parameters
description: 'Service Name'
type: string
required: true
And now, we use these parameters in the workflow execution and automatize the process.
jobs:
scaffolding:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
echo "Building ${{ inputs.serviceName }} on ${{ inputs.tenant }}"
python3 -m pip install --user cookiecutter
python3 -m cookiecutter -s -f --no-input ${{ github.workspace }}/_template tenant=${{ inputs.tenant }} service=${{ inputs.serviceName }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.TOKEN }}
title: "Adding service ${{ inputs.serviceName }} to ${{ inputs.tenant }}"
branch: feat/add-${{ inputs.serviceName }}
We can create a CODEOWNERS
file set up the PR’s approvers for each tenant. Here more information.
You can find the full code in the repository