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 TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ COPY go.mod go.sum ./
|
|||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
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
|
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:
|
services:
|
||||||
routingtabletowg:
|
routingtabletowg:
|
||||||
image: ruakij/routingtabletowg
|
image: ghcr.io/ruakij/routingtabletowg
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
network_mode: host
|
network_mode: host
|
||||||
cap_add:
|
cap_add:
|
||||||
@@ -76,9 +76,21 @@ services:
|
|||||||
|
|
||||||
### 1.2.3. Without Docker
|
### 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>
|
<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