Replace Jenkinsfile with GitHub Actions CI, release and lint tooling
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
.git
|
||||
/bin
|
||||
/dist
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
go mod tidy -diff
|
||||
|
||||
files=$(git diff --cached --name-only --diff-filter=ACM -- '*.go')
|
||||
[ -n "$files" ] || exit 0
|
||||
pkgs=$(echo "$files" | xargs -n1 dirname | sort -u | sed 's|^|./|')
|
||||
|
||||
unformatted=$(gofmt -l $files)
|
||||
if [ -n "$unformatted" ]; then
|
||||
echo "gofmt: $unformatted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The program is Linux-only (netlink), so everything is checked for Linux.
|
||||
export GOOS=linux
|
||||
|
||||
go vet $pkgs
|
||||
|
||||
# Test binaries only run on a Linux host; elsewhere they are compiled, not run.
|
||||
if [ "$(go env GOHOSTOS)" = linux ]; then
|
||||
go test -race $pkgs
|
||||
else
|
||||
go test -exec /usr/bin/true $pkgs
|
||||
fi
|
||||
|
||||
if command -v golangci-lint >/dev/null; then
|
||||
golangci-lint run $pkgs
|
||||
fi
|
||||
@@ -0,0 +1,26 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
go-dependencies:
|
||||
patterns: ["*"]
|
||||
update-types: [minor, patch]
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
actions:
|
||||
patterns: ["*"]
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
base-images:
|
||||
patterns: ["*"]
|
||||
@@ -0,0 +1,83 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# A CVE published after a merge is still our problem, so rescan daily.
|
||||
schedule:
|
||||
- cron: "0 4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# A push supersedes the run of the commit before it, so drop that one instead of
|
||||
# waiting for a verdict on code nobody has any more.
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
go:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- run: gofmt -l cmd lib | tee /dev/stderr | (! read -r)
|
||||
- run: go mod tidy -diff
|
||||
- run: go vet ./...
|
||||
- run: go test -race ./...
|
||||
- run: make build
|
||||
# Read from a plain file so the upstream-sync workflow can bump it without a
|
||||
# token carrying the workflow scope.
|
||||
- id: lint-version
|
||||
run: echo "version=$(cat hack/golangci-lint.version)" >> "$GITHUB_OUTPUT"
|
||||
- uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: ${{ steps.lint-version.outputs.version }}
|
||||
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
# Reachability-aware, so it only fails on vulnerabilities we actually call.
|
||||
# It installs its own Go, hence no setup-go step; go-version-input must be
|
||||
# cleared or it collides with go-version-file.
|
||||
- uses: golang/govulncheck-action@v1.1.0
|
||||
with:
|
||||
repo-checkout: false
|
||||
go-version-file: go.mod
|
||||
go-version-input: ""
|
||||
- uses: aquasecurity/trivy-action@v0.36.0
|
||||
with:
|
||||
scan-type: fs
|
||||
scan-ref: .
|
||||
scanners: vuln,secret
|
||||
format: table
|
||||
exit-code: "1"
|
||||
ignore-unfixed: true
|
||||
severity: CRITICAL,HIGH
|
||||
|
||||
image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
load: true
|
||||
tags: routingtabletowg:ci
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- uses: aquasecurity/trivy-action@v0.36.0
|
||||
with:
|
||||
image-ref: routingtabletowg:ci
|
||||
format: table
|
||||
exit-code: "1"
|
||||
ignore-unfixed: true
|
||||
severity: CRITICAL,HIGH
|
||||
@@ -0,0 +1,68 @@
|
||||
name: release
|
||||
|
||||
# 1.2.3 is a release, anything with a suffix (1.2.3-rc.1) a prerelease. The tags
|
||||
# carry no v prefix.
|
||||
on:
|
||||
push:
|
||||
tags: ["[0-9]+.[0-9]+.[0-9]+*"]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
# Emulation for the RUN steps of the non-native platforms.
|
||||
- uses: docker/setup-qemu-action@v4
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
# The tag is v-less already, so {{version}} is the tag itself. major.minor and
|
||||
# major are skipped for prereleases by the action itself.
|
||||
- id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
- uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
sbom: true
|
||||
provenance: mode=max
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: image
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Create the GitHub release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
flags=()
|
||||
case "${GITHUB_REF_NAME}" in
|
||||
*-*) flags+=(--prerelease) ;;
|
||||
# Notes for a stable release span back to the previous stable tag in its
|
||||
# history, not to the last RC or a newer release on another branch.
|
||||
*)
|
||||
prev=$(git describe --tags --abbrev=0 --match '[0-9]*' --exclude '*-*' "${GITHUB_REF_NAME}^" 2>/dev/null || true)
|
||||
[ -n "${prev}" ] && flags+=(--notes-start-tag "${prev}")
|
||||
;;
|
||||
esac
|
||||
gh release create "${GITHUB_REF_NAME}" --verify-tag --generate-notes "${flags[@]}"
|
||||
@@ -0,0 +1,75 @@
|
||||
# The golangci-lint version lives in hack/golangci-lint.version, which Dependabot
|
||||
# cannot parse. This bumps it and opens a PR.
|
||||
#
|
||||
# Events caused by GITHUB_TOKEN start no workflows. AUTOMATION_SSH_KEY is an optional
|
||||
# repository secret holding the private half of a deploy key with write access; the
|
||||
# branch is pushed over SSH with it, so pushes to an open PR run ci.yaml. Opening the PR
|
||||
# is still a GITHUB_TOKEN event, so a new PR gets its checks from a dispatched run on
|
||||
# its branch, as workflow_dispatch is the exception to that rule.
|
||||
name: upstream-sync
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "17 4 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
golangci-lint:
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: upstream-sync-golangci-lint
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ssh-key: ${{ secrets.AUTOMATION_SSH_KEY }}
|
||||
|
||||
- id: detect
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
current=$(cat hack/golangci-lint.version)
|
||||
latest=$(gh release view --repo golangci/golangci-lint --json tagName -q .tagName)
|
||||
echo "current=${current}" >> "$GITHUB_OUTPUT"
|
||||
echo "latest=${latest}" >> "$GITHUB_OUTPUT"
|
||||
[ "${current}" = "${latest}" ] && echo "changed=false" >> "$GITHUB_OUTPUT" || echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- if: steps.detect.outputs.changed == 'true'
|
||||
run: echo "${{ steps.detect.outputs.latest }}" > hack/golangci-lint.version
|
||||
|
||||
# A new release usually means new checks, so let the PR say whether we pass.
|
||||
- if: steps.detect.outputs.changed == 'true'
|
||||
id: lint
|
||||
continue-on-error: true
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: ${{ steps.detect.outputs.latest }}
|
||||
|
||||
- if: steps.detect.outputs.changed == 'true'
|
||||
id: pr
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
branch: automation/golangci-lint-version-sync
|
||||
delete-branch: true
|
||||
commit-message: "Bump golangci-lint to ${{ steps.detect.outputs.latest }}"
|
||||
title: "Bump golangci-lint to ${{ steps.detect.outputs.latest }}"
|
||||
body: |
|
||||
Automated golangci-lint upstream sync.
|
||||
|
||||
- Previous: `${{ steps.detect.outputs.current }}`
|
||||
- New: `${{ steps.detect.outputs.latest }}`
|
||||
|
||||
Result of running the new version against the tree: `${{ steps.lint.outcome }}`.
|
||||
A failure here is expected when a release adds checks; the findings are in the
|
||||
job log of the run that opened this PR.
|
||||
|
||||
- if: steps.pr.outputs.pull-request-operation == 'created'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh workflow run ci.yaml --ref automation/golangci-lint-version-sync
|
||||
@@ -0,0 +1,8 @@
|
||||
/bin
|
||||
/dist
|
||||
.*
|
||||
!.gitignore
|
||||
!.githooks
|
||||
!.github
|
||||
!.dockerignore
|
||||
!.golangci.yml
|
||||
@@ -0,0 +1,21 @@
|
||||
version: "2"
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
- contextcheck
|
||||
- errorlint
|
||||
- gocritic
|
||||
- nilerr
|
||||
- rowserrcheck
|
||||
- unconvert
|
||||
- wastedassign
|
||||
- revive
|
||||
settings:
|
||||
revive:
|
||||
rules:
|
||||
- name: unused-parameter
|
||||
exclusions:
|
||||
presets:
|
||||
# Close and os.Remove on cleanup paths, with nothing to report the error to.
|
||||
- std-error-handling
|
||||
+2
-1
@@ -4,6 +4,7 @@ FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS build
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
@@ -11,7 +12,7 @@ COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
|
||||
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} GOARM=${TARGETVARIANT#v} \
|
||||
go build -trimpath -ldflags "-s -w" -o app ./cmd/app
|
||||
|
||||
|
||||
|
||||
Vendored
-102
@@ -1,102 +0,0 @@
|
||||
def IMAGE_TAG = ""
|
||||
pipeline {
|
||||
agent {
|
||||
kubernetes {
|
||||
yaml """
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kaniko
|
||||
spec:
|
||||
containers:
|
||||
- name: kaniko
|
||||
image: gcr.io/kaniko-project/executor:debug
|
||||
imagePullPolicy: Always
|
||||
command:
|
||||
- /busybox/cat
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- name: jenkins-docker-cfg
|
||||
mountPath: /kaniko/.docker
|
||||
volumes:
|
||||
- name: jenkins-docker-cfg
|
||||
projected:
|
||||
sources:
|
||||
- secret:
|
||||
name: docker-credentials
|
||||
items:
|
||||
- key: data
|
||||
path: config.json
|
||||
"""
|
||||
}
|
||||
}
|
||||
environment {
|
||||
IMAGE_PUSH_DESTINATION="ghcr.io/ruakij/routingtabletowg"
|
||||
}
|
||||
stages {
|
||||
stage("Pre-build") {
|
||||
steps {
|
||||
|
||||
script{
|
||||
//checkout scm
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: scm.branches,
|
||||
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
|
||||
extensions: scm.extensions + [[$class: 'CloneOption', noTags: false, reference: '', shallow: true]],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: scm.userRemoteConfigs
|
||||
])
|
||||
|
||||
def version = sh (returnStdout: true, script: "git describe --tags --long --always $GIT_COMMIT").trim()
|
||||
def gitCommit = sh (returnStdout: true, script: "git rev-parse --short $GIT_COMMIT").trim()
|
||||
echo "Version: $version"
|
||||
echo "Git Commit: $gitCommit"
|
||||
|
||||
IMAGE_TAG = "--destination $IMAGE_PUSH_DESTINATION:$gitCommit "
|
||||
|
||||
if (GIT_BRANCH == "main") {
|
||||
IMAGE_TAG += "--destination $IMAGE_PUSH_DESTINATION:latest "
|
||||
|
||||
if(version != gitCommit){
|
||||
def parts = version.split('.')
|
||||
if(parts.size() > 0){
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
def versionTag = parts[0..i].join(".")
|
||||
IMAGE_TAG += "--destination $IMAGE_PUSH_DESTINATION:$versionTag "
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IMAGE_TAG += "--destination $IMAGE_PUSH_DESTINATION:$GIT_BRANCH "
|
||||
|
||||
if(version != gitCommit){
|
||||
def parts = version.split('.')
|
||||
if(parts.size() > 0){
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
def versionTag = parts[0..i].join(".")
|
||||
IMAGE_TAG += "--destination $IMAGE_PUSH_DESTINATION:$GIT_BRANCH-$versionTag "
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "Image-Tags: $IMAGE_TAG"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build with Kaniko') {
|
||||
steps {
|
||||
container(name: 'kaniko', shell: '/busybox/sh') {
|
||||
withEnv(['PATH+EXTRA=/busybox', "IMAGE_TAG=$IMAGE_TAG"]) {
|
||||
// Use the image tag variable as part of the image name when you build and push the image with kaniko
|
||||
sh '''#!/busybox/sh
|
||||
/kaniko/executor --context `pwd` --force $IMAGE_TAG
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
LDFLAGS = -s -w
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags "$(LDFLAGS)" -o bin/routingtabletowg ./cmd/app
|
||||
@@ -62,7 +62,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
routingtabletowg:
|
||||
image: ruakij/routingtabletowg
|
||||
image: ghcr.io/ruakij/routingtabletowg
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
cap_add:
|
||||
@@ -76,9 +76,21 @@ services:
|
||||
|
||||
### 1.2.3. Without Docker
|
||||
|
||||
Clone the Repository `git clone <URI>` and build the Program with `go build cmd/app`
|
||||
Requires Go 1.27.3 or newer and Linux.
|
||||
|
||||
Then you can run it with `./app`
|
||||
Clone the Repository `git clone <URI>` and build the Program with `make build` (or `go build ./cmd/app`)
|
||||
|
||||
Then you can run it with `./bin/routingtabletowg`
|
||||
|
||||
<br>
|
||||
|
||||
### 1.2.4. Development
|
||||
|
||||
Enable the pre-commit hook (formatting, `go vet`, tests, `golangci-lint`) with `git config core.hooksPath .githooks`.
|
||||
|
||||
The program only builds for Linux; on other systems set `GOOS=linux` for `go vet` and `golangci-lint`.
|
||||
|
||||
CI runs on GitHub Actions. Pushing a tag like `1.2.3` publishes `ghcr.io/ruakij/routingtabletowg` for `linux/amd64`, `linux/arm64` and `linux/arm/v7` and creates a GitHub release.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
TAG="ruakij/routingtabletowg"
|
||||
PLATFORM="linux/amd64,linux/arm64/v8,linux/arm/v7"
|
||||
EXTRA_ARGS="$@"
|
||||
|
||||
docker buildx build \
|
||||
--platform $PLATFORM \
|
||||
--tag $TAG \
|
||||
$EXTRA_ARGS \
|
||||
.
|
||||
@@ -1,7 +0,0 @@
|
||||
TAG="ruakij/routingtabletowg"
|
||||
EXTRA_ARGS="$@"
|
||||
|
||||
docker build \
|
||||
--tag $TAG \
|
||||
$EXTRA_ARGS \
|
||||
.
|
||||
@@ -0,0 +1 @@
|
||||
v2.15.0
|
||||
Reference in New Issue
Block a user