Sruput - Container Builder Workflow
Simple Container Build & Release using GitHub Action Workflow.
This template is used to immediately copy a workflow in this repo to make your own builder for your custom project.
How to use
Simply copy the workflow and create a minimal config file called sruput.yaml
.
The file should point to your build/release matrix or parameters.
Behaviour
Sruput GH Action will read the config file and then you can use the processed output for your other action.
Main use case: for a docker build release
This is an example for the workflow to build and release docker image :
name: latest-build
on:
workflow_dispatch:
inputs:
tags:
description: 'Git tag to use'
pull_request:
branches:
- develop
- main
push:
branches:
- develop
- main
tags:
- '*.*.*.'
jobs:
build-push:
runs-on: ubuntu-latest
strategy:
matrix:
image-variant:
- debian
- alpine
image-target:
- prod
- dev
env:
APP_IMAGE: lucernae/myapp
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Sruput docker context
id: sruput_docker_meta
uses: lucernae/sruput-action@v1
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v3
with:
images: ${{ steps.sruput_docker_meta.outputs.repo_owner }}/${{ steps.sruput_docker_meta.outputs.repo_name }}
tags: |
type=semver,pattern=\d.\d.\d
type=ref,event=branch
type=ref,event=pr
- name: Sruput docker build
id: sruput_docker_build
uses: lucernae/sruput-action@v1
with:
param: |
docker-meta-tags: ${{ steps.docker_meta.outputs.tags}}
variant: ${{ matrix.image-variant }}
target: ${{ matrix.image-target }}
- name: Build image
uses: docker/build-push-action@v2
with:
context: .
file: ${{ steps.sruput_docker_build.outputs.dockerfile }}
push: ${{ steps.sruput_docker_build.outputs.push }}
load: ${{ steps.sruput_docker_build.outputs.load }}
target: ${{ steps.sruput_docker_build.outputs.target }}
tags: ${{ steps.sruput_docker_build.outputs.tags }}
cache-from: |
type=gha,scope=${{ steps.sruput_docker_build.outputs.target }}
cache-to: type=gha,scope=${{ steps.sruput_docker_build.outputs.target }}
In the above workflow, the final step is to build and push a docker image.
However the decision and parameters of the build depends on the context collected
by the Sruput action. How Sruput collect this meta information depends on the file
described in sruput.yaml
.
repo-owner:
- type: github-action
context-path: 'github.repository_owner'
repo-name:
- type: github-action
context-path: 'github.repository.name'
variant:
target:
full-variant-name:
- scalar: '{param["variant"]}--{param["target"]}'
# If it contains 'prod' target, omit it, because it's the default.
- type: replace
regex-match: '--prod'
regex-replace: ''
input: '{param["full-variant-name"]}'
tags:
- and:
- type: replace
regex-match: 'develop'
regex-replace: 'latest'
input: '{param["docker-meta-tags"]}'
- type: replace
regex-match: 'main'
regex-replace: 'stable'
input: '{param["docker-meta-tags"]}'
# image tag for a semver release +
# image tag for canonical release (with added calver segments)
- type: replace
regex-match: '(\d.\d.\d)'
regex-replace: |
{param["full-variant-name"]}--\\1
{param["full-variant-name"]}--\\1--{param["calver"]}
input: '{param["docker-meta-tags"]}'
dockerfile:
- scalar: 'variants/{param["variant"]}/Dockerfile'
push:
# we can only push if it is commit changes of the same repo or
# PR from the same repository.
- equal:
- scalar: '{github.event.pull_request.base.repo.url}'
- scalar: '{github.event.pull_request.head.repo.url}'
load:
- scalar: false
By separating the meta context and the workflows, we decoupled the rule-based inference with the action itself.
This way, you can refactor both separately. You can use the approach to organize the same rules of meta-handling via sruput.yaml
.
If in the future your action needs update, you can refactor it easily, or let bot do that.
The merit works both ways. If there are new repo and you want to enforce the same meta-handling rules, you just need to copy sruput.yaml
.
One central entity in your org then can easily check using automated tools if a repo is conformant with the current applied settings.
Optional Use Case: Git Release
Normally you create a git release or tags by yourself. For big project with composite dependencies, it is often useful to decouple the workflow to create a release, with the PR to prepare the release.
The benefit of this approach:
- Release manager can create a PR and then fill in the release details, such as:
- Changelogs
- Software version and metadata to be extracted by workflows
- Git tag and release information is extracted from the metadata within the repo itself
- Simplify Release Approval by discussion in the PR
- Can be hooked to an automatic action to immediately publish the release (or schedule it) via workflow on PR merge
sruput.yaml
can act as a linter or dry-running the release process by checking the resulting metadata
An example workflow action to create a Github Release