Files
actions/go-build/action.yml

263 lines
8.6 KiB
YAML

# yaml-language-server: $schema=https://json.schemastore.org/github-action.json
# permissions:
# - contents: read # Required for checking out repository
---
name: Go Build
description: 'Builds the Go project.'
author: 'Ismo Vuorinen'
branding:
icon: package
color: blue
inputs:
go-version:
description: 'Go version to use.'
required: false
destination:
description: 'Build destination directory.'
required: false
default: './bin'
max-retries:
description: 'Maximum number of retry attempts for go mod download operations'
required: false
default: '3'
token:
description: 'GitHub token for authentication'
required: false
default: ''
outputs:
build_status:
description: 'Build completion status (success/failure)'
value: ${{ steps.build.outputs.status }}
test_status:
description: 'Test execution status (success/failure/skipped)'
value: ${{ steps.test.outputs.status }}
go_version:
description: 'Version of Go used'
value: ${{ steps.detect-go-version.outputs.detected-version }}
binary_path:
description: 'Path to built binaries'
value: ${{ inputs.destination }}
coverage_path:
description: 'Path to coverage report'
value: 'coverage.out'
runs:
using: composite
steps:
- name: Checkout Repository
uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
with:
token: ${{ inputs.token || github.token }}
- name: Detect Go Version
id: detect-go-version
shell: sh
env:
DEFAULT_VERSION: "${{ inputs.go-version || '1.24' }}"
run: |
set -eu
# Function to validate version format
validate_version() {
version=$1
case "$version" in
[0-9]*\.[0-9]* | [0-9]*\.[0-9]*\.[0-9]*)
return 0
;;
*)
return 1
;;
esac
}
# Function to clean version string
clean_version() {
printf '%s' "$1" | sed 's/^[vV]//' | tr -d ' \n\r'
}
detected_version=""
# Parse .tool-versions file
if [ -f .tool-versions ]; then
echo "Checking .tool-versions for golang..." >&2
version=$(awk '/^golang[[:space:]]/ {gsub(/#.*/, ""); print $2; exit}' .tool-versions 2>/dev/null || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found Go version in .tool-versions: $version" >&2
detected_version="$version"
fi
fi
fi
# Parse Dockerfile
if [ -z "$detected_version" ] && [ -f Dockerfile ]; then
echo "Checking Dockerfile for golang..." >&2
version=$(grep -iF "FROM" Dockerfile | grep -F "golang:" | head -1 | \
sed -n -E "s/.*golang:([0-9]+(\.[0-9]+)*)(-[^:]*)?.*/\1/p" || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found Go version in Dockerfile: $version" >&2
detected_version="$version"
fi
fi
fi
# Parse devcontainer.json
if [ -z "$detected_version" ] && [ -f .devcontainer/devcontainer.json ]; then
echo "Checking devcontainer.json for golang..." >&2
if command -v jq >/dev/null 2>&1; then
version=$(jq -r '.image // empty' .devcontainer/devcontainer.json 2>/dev/null | sed -n -E "s/.*golang:([0-9]+(\.[0-9]+)*)(-[^:]*)?. */\1/p" || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found Go version in devcontainer: $version" >&2
detected_version="$version"
fi
fi
fi
fi
# Parse .go-version file
if [ -z "$detected_version" ] && [ -f .go-version ]; then
echo "Checking .go-version..." >&2
version=$(tr -d '\r' < .go-version | head -1)
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found Go version in .go-version: $version" >&2
detected_version="$version"
fi
fi
fi
# Parse go.mod
if [ -z "$detected_version" ] && [ -f go.mod ]; then
echo "Checking go.mod..." >&2
version=$(grep -E '^go[[:space:]]+[0-9]' go.mod | awk '{print $2}' | head -1 || echo "")
if [ -n "$version" ]; then
version=$(clean_version "$version")
if validate_version "$version"; then
echo "Found Go version in go.mod: $version" >&2
detected_version="$version"
fi
fi
fi
# Use default version if nothing detected
if [ -z "$detected_version" ]; then
detected_version="$DEFAULT_VERSION"
echo "Using default Go version: $detected_version" >&2
fi
# Set output
printf 'detected-version=%s\n' "$detected_version" >> "$GITHUB_OUTPUT"
echo "Final detected Go version: $detected_version" >&2
- name: Setup Go
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
with:
go-version: ${{ steps.detect-go-version.outputs.detected-version }}
cache: true
- name: Download Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}
command: |
echo "Downloading Go dependencies..."
go mod download
go mod verify
- name: Build Go Project
id: build
shell: sh
env:
DESTINATION: ${{ inputs.destination }}
run: |
set -eu
echo "Building Go project..."
# Create destination directory
mkdir -p "$DESTINATION"
build_success=true
# Check if there are any main packages
if find . -name "*.go" -exec grep -l "package main" {} \; | head -1 | grep -q .; then
# Build all main packages
find . -name "*.go" -exec grep -l "package main" {} \; | xargs dirname | sort -u | while IFS= read -r main_dir; do
echo "Building package in $main_dir..."
output_name=$(basename -- "$main_dir")
if ! go build -ldflags="-s -w" -o "$DESTINATION/$output_name" "$main_dir"; then
build_success=false
fi
done
else
echo "No main packages found, building library..."
if ! go build ./...; then
build_success=false
fi
fi
if [ "$build_success" = true ]; then
echo "status=success" >> "$GITHUB_OUTPUT"
echo "Build completed successfully"
else
echo "status=failure" >> "$GITHUB_OUTPUT"
echo "Build failed"
exit 1
fi
- name: Run Tests
id: test
shell: sh
run: |
set -eu
echo "Running Go tests..."
if find . -name "*_test.go" | grep -q .; then
# Check if race detector is supported on this platform
# The race detector is only supported on specific GOOS/GOARCH combinations:
# linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64,
# freebsd/amd64, netbsd/amd64
RACE_FLAG=""
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
case "${GOOS}/${GOARCH}" in
linux/amd64|linux/arm64|darwin/amd64|darwin/arm64|windows/amd64|freebsd/amd64|netbsd/amd64)
RACE_FLAG="-race"
echo "Race detector enabled for ${GOOS}/${GOARCH}"
;;
*)
echo "Race detector not supported on ${GOOS}/${GOARCH}, skipping -race flag"
;;
esac
if go test -v ./... $RACE_FLAG -coverprofile=coverage.out; then
echo "status=success" >> "$GITHUB_OUTPUT"
echo "Tests completed successfully"
else
echo "status=failure" >> "$GITHUB_OUTPUT"
echo "Tests failed"
exit 1
fi
else
echo "No test files found, skipping test execution."
echo "status=skipped" >> "$GITHUB_OUTPUT"
fi
- name: Upload Build Artifacts
if: always()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: go-build-artifacts
path: |
${{ inputs.destination }}/*
coverage.out
if-no-files-found: ignore