I like to write code, build, and release tooling, for my brain at 3 AM. No surprises, no clever bits to trip me up. Lately I’ve been playing with GitHub Actions to build and deploy some of my public projects. It took a little while to figure out something that I could copy and paste between them, and I’d like to share what I’ve managed to come up with.
Build Actions
Committed to your project as .github/workflows/build.yml
. These actions trigger whenever to you push to your master/main branch, or to a PR off your master/main branch.
Java
---
name: "java-build"
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: "Set up JDK 11"
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
- name: Build
run: make build
Go
name: "go-build"
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: "Set up Go"
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Build
run: make build
Release Actions
Committed to your project as .github/workflows/release.yml
. These actions trigger whenever you push a tag with v
as its prefix. Please note that the automatic releases action will fail if your tag does not follow a semantic versioning format.
Java
---
name: "tagged-release"
on:
push:
tags:
- "v*"
jobs:
tagged-release:
name: "Tagged Release"
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v2
- name: "Set up JDK 11"
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
- name: "Release Build"
run: make release
- name: "Automatic Releases"
uses: marvinpinto/action-automatic-releases@v1.2.0
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
LICENSE*
build/libs/*.jar
Go
---
name: "tagged-release"
on:
push:
tags:
- "v*"
jobs:
tagged-release:
name: "Tagged Release"
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v2
- name: "Set up Go"
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: "Release Build"
run: make release
- name: "Automatic Releases"
uses: marvinpinto/action-automatic-releases@v1.2.0
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
LICENSE*
target/*
Example Makefiles
I use Makefiles to coordinate language-specific and generic build and deploy tasks, so all these actions wind up triggering a make target rather than a language-specific build tool. It also means that I can come back to a project and know how to build it without needing to immediately remember language-specific build tool incantations.
Java
GIT_TAG := $(shell git describe --tags 2>/dev/null)
.PHONY: build
build: clean
./gradlew --console plain -Pversion=dev
.PHONY:
release: clean
./gradlew --console plain -Pversion=${GIT_TAG}
.PHONY: clean
clean:
rm -rf build
.PHONY: deps
deps:
./gradlew dependencies
Go
GIT_TAG := $(shell git describe --tags 2>/dev/null)
.PHONY: build
build: clean test compile
.PHONY: clean
clean:
rm -rf target
.PHONY: test
test:
go test ./...
.PHONY: compile
compile:
go build -o target/project ./project/...
.PHONY: release
release: clean
GOOS=linux GOARCH=amd64 go build -o target/project-${GIT_TAG}-linux ./project/...
GOOS=darwin GOARCH=amd64 go build -o target/project-${GIT_TAG}-darwin ./project/...
Hope you find this useful.