1
0

ci: introduce
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
Konstantin Demin 2024-02-25 17:12:47 +03:00
parent 51e14d687f
commit 64e680f0fc
Signed by: krd
GPG Key ID: 1F33CB0BA4731BC6
12 changed files with 434 additions and 3 deletions

27
.ci/build-all.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
set -ef
[ -z "${CI_DEBUG}" ] || set -xv
TARGET_PLATFORMS=$(printf '%s' "${TARGET_PLATFORMS:?}" | tr ',' ' ')
for TARGET_PLATFORM in ${TARGET_PLATFORMS} ; do
r=0
[ -n "${TARGET_PLATFORM}" ] || r=1
[ "$r" = 0 ] || break
export TARGET_PLATFORM
.ci/env.sh || r=$?
[ "$r" = 0 ] || break
head -n 40 .build_env
. ./.build_env
[ -n "${GOARCH}" ] || r=1
[ "$r" = 0 ] || break
.ci/build.sh || r=$?
[ "$r" = 0 ] || break
done
.ci/build-cleanup.sh
exit "$r"

9
.ci/build-cleanup.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -ef
[ -z "${CI_DEBUG}" ] || set -xv
## cleanup build
GOCACHE=$(go env GOCACHE)
GOMODCACHE=$(go env GOMODCACHE)
rm -rf "${GOCACHE:?}" "${GOMODCACHE:?}"

19
.ci/build.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
set -ef
[ -z "${CI_DEBUG}" ] || set -xv
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
mkdir -p dist
export OUTDIR=dist
export OUTSFX="-${GOOS:?}-${GOARCH:?}"
idle() {
nice -n +40 \
chrt -i 0 \
ionice -c 3 \
"$@"
}
idle make clean build || make clean build

107
.ci/env.sh Executable file
View File

@ -0,0 +1,107 @@
#!/bin/sh
set -ef
## authentication in image registry
printf '%s' "${REGISTRY_AUTH}" > .auth.json
[ -z "${CI_DEBUG}" ] || set -xv
## flush build env
: > .build_env
echo "unset GOAMD64 GOARM GOPPC64 GOMIPS GOMIPS64" >> .build_env
echo "set -a" >> .build_env
## shifty-nifty shell goodies :)
## do same thing as GitLab does for CI_COMMIT_REF_SLUG:
## 1. lowercase string
## 2. replace not allowed chars with '-' (squeezing repeats)
## allowed chars are: `0-9`, `a-z` and '-'
## 3. remove leading and trailing '-' (if any)
## 4. truncate string up to 63 chars
## 5. remove trailing '-' (if any)
ref_slug() {
printf '%s' "${1:?}" \
| sed -Ez 's/^(.+)$/\L\1/;s/[^0-9a-z]+/-/g;s/^-//;s/-$//;s/^(.{1,63}).*$/\1/;s/-$//' \
| tr -d '\0'
}
## normalize image tag
## performs like ref_slug() except:
## - symbols '_' and '.' are allowed too
## - truncate string up to 96 chars
## - squeeze symbol sequences:
## - '-' has higher priority than surrounding (leading and trailing) symbols
## - first symbol in sequence has higher priority than following symbols
## NB: implementation is rather demonstrative than effective
image_tag_norm() {
printf '%s' "${1:?}" \
| sed -Ez 's/^(.+)$/\L\1/;s/[^0-9a-z_.]+/-/g' \
| sed -Ez 's/\.+/./g;s/_+/_/g;s/[_.]+-/-/g;s/-[_.]+/-/g;s/([_.])[_.]+/\1/g' \
| sed -Ez 's/^[_.-]//;s/[_.-]$//;s/^(.{1,95}).*$/\1/;s/[_.-]$//' \
| tr -d '\0'
}
## produce GOOS and GOARCH from TARGET_PLATFORM
unset GOOS GOARCH _variant
IFS=/ read -r GOOS GOARCH _variant <<-EOF
${TARGET_PLATFORM}
EOF
## verify that GOOS and GOARCH are not empty
: "${GOOS:?}" "${GOARCH:?}"
## fill .build_env with Go-related variables
echo "GOOS=${GOOS}" >> .build_env
echo "GOARCH=${GOARCH}" >> .build_env
if [ -n "${_variant}" ] ; then
case "${GOARCH}" in
amd64 )
echo "GOAMD64=${_variant}" >> .build_env ;;
arm )
_variant=${_variant#v}
echo "GOARM=${_variant}" >> .build_env
;;
ppc64 | ppc64le )
echo "GOPPC64=${_variant}" >> .build_env ;;
mips | mipsle )
echo "GOMIPS=${_variant}" >> .build_env ;;
mips64 | mips64le )
echo "GOMIPS64=${_variant}" >> .build_env ;;
esac
fi
## misc CI things
# CI_COMMIT_SHORT_SHA="${CI_COMMIT_SHA:0:8}"
CI_COMMIT_SHORT_SHA=$(printf '%s' "${CI_COMMIT_SHA}" | cut -c 1-8)
echo "CI_COMMIT_SHORT_SHA=${CI_COMMIT_SHORT_SHA}" >> .build_env
CI_COMMIT_REF_SLUG="$(ref_slug "${CI_COMMIT_BRANCH}")"
if [ -n "${CI_COMMIT_SOURCE_BRANCH}" ] ; then
CI_COMMIT_REF_SLUG="$(ref_slug "${CI_COMMIT_SOURCE_BRANCH}")"
fi
echo "CI_COMMIT_REF_SLUG=${CI_COMMIT_REF_SLUG}" >> .build_env
## image tag(s)
IMAGE_TAG="${CI_COMMIT_SHORT_SHA}-b${CI_PIPELINE_NUMBER}-${CI_COMMIT_REF_SLUG}"
if [ -n "${CI_COMMIT_SOURCE_BRANCH}" ] ; then
echo "Running on branch '${CI_COMMIT_SOURCE_BRANCH}'"
else
if [ "${CI_COMMIT_BRANCH}" != "${CI_REPO_DEFAULT_BRANCH}" ] ; then
echo "Running on branch '${CI_COMMIT_BRANCH}'"
else
IMAGE_TAG="${CI_COMMIT_SHORT_SHA}"
fi
fi
IMAGE_TAG=$(image_tag_norm "${IMAGE_TAG}")
echo "IMAGE_TAG=${IMAGE_TAG}" >> .build_env
## extra tag(s)
tags=$(image_tag_norm "branch-${CI_COMMIT_BRANCH}")
if [ -n "${CI_COMMIT_TAG}" ] ; then
tags="${CI_COMMIT_TAG#v}"
fi
if [ "${CI_COMMIT_BRANCH}" = "${CI_REPO_DEFAULT_BRANCH}" ] ; then
tags="${tags} ${VERSION} latest"
echo "RELMODE=1" >> .build_env
fi
echo "EXTRA_TAGS='${tags}'" >> .build_env
echo "set +a" >> .build_env

70
.ci/image-all.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/sh
set -ef
[ -z "${CI_DEBUG}" ] || set -xv
: "${TARGET_PLATFORMS:?}"
## semi-dry run
TARGET_PLATFORM=linux/amd64 \
.ci/env.sh
. ./.build_env
## setup image registry authentication
export REGISTRY_AUTH_FILE="${PWD}/.auth.json"
[ -s "${REGISTRY_AUTH_FILE}" ] || exit 1
buildah login "${IMAGE_REGISTRY:?}"
: "${IMAGE_NAME:?}" "${IMAGE_TAG:?}"
IMAGE="${IMAGE_NAME}:${IMAGE_TAG}"
export IMAGE_MANIFEST="${IMAGE}"
if buildah manifest exists "${IMAGE}" ; then
buildah manifest rm "${IMAGE}"
fi
buildah manifest create "${IMAGE}"
TARGET_PLATFORMS=$(printf '%s' "${TARGET_PLATFORMS}" | tr ',' ' ')
for TARGET_PLATFORM in ${TARGET_PLATFORMS} ; do
r=0
[ -n "${TARGET_PLATFORM}" ] || r=1
[ "$r" = 0 ] || break
export TARGET_PLATFORM
.ci/env.sh || r=$?
[ "$r" = 0 ] || break
head -n 40 .build_env
. ./.build_env
[ -n "${GOARCH}" ] || r=1
[ "$r" = 0 ] || break
# PLATFORM_SUFFIX='-'$(printf '%s' "${TARGET_PLATFORM}" | tr '/' '-')
PLATFORM_SUFFIX="-${GOOS:?}-${GOARCH:?}"
export PLATFORM_SUFFIX
.ci/image.sh || r=$?
[ "$r" = 0 ] || break
buildah manifest add "${IMAGE}" "${IMAGE}${PLATFORM_SUFFIX}"
done
[ "$r" = 0 ] || exit "$r"
## list built image(s)
echo
echo 'IMAGES:'
echo
buildah images --all --noheading --format 'table {{.ID}} {{.Name}}:{{.Tag}} {{.Size}} {{.CreatedAtRaw}}'
echo
## push image(s) and manifest(s)
buildah manifest push --all "${IMAGE}" "docker://${IMAGE}"
for tag in ${EXTRA_TAGS} ; do
[ -n "${tag}" ] || continue
if [ "${tag}" = "${IMAGE_TAG}" ] ; then continue ; fi
buildah manifest push --all "${IMAGE}" "docker://${IMAGE_NAME}:${tag}"
done

23
.ci/image.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh
set -ef
[ -z "${CI_DEBUG}" ] || set -xv
## setup image registry authentication
export REGISTRY_AUTH_FILE="${PWD}/.auth.json"
[ -s "${REGISTRY_AUTH_FILE}" ] || exit 1
## produce _real_ BASE_IMAGE because "static-debian12:debug-nonroot" is not multiarch image (yet)
export BASE_IMAGE="${BASE_IMAGE:?}-${GOARCH:?}"
## build image
buildah bud \
-t "${IMAGE_NAME}:${IMAGE_TAG}${PLATFORM_SUFFIX}" \
-f ./Dockerfile.ci \
${IMAGE_MANIFEST:+ --manifest "${IMAGE_MANIFEST}" } \
--platform "${TARGET_PLATFORM}" \
--build-arg "TARGET_PLATFORM=${TARGET_PLATFORM}" \
--build-arg "PLATFORM_SUFFIX=${PLATFORM_SUFFIX}" \
--build-arg "BASE_IMAGE=${BASE_IMAGE}" \
--build-arg "VERSION=${VERSION}" \
--network=host

5
.gitignore vendored
View File

@ -1 +1,4 @@
/plugin-sonatype-nexus
/plugin-sonatype-nexus
/.auth.json
/.build_env
/dist/

58
.woodpecker/.build.yml Normal file
View File

@ -0,0 +1,58 @@
when:
event: [ push, tag, cron, manual ]
variables:
- &image_registry 'docker.io'
- &image_name 'docker.io/rockdrilla/woodpecker-sonatype-nexus'
- &version '0.0.1'
- &buildah_image 'quay.io/containers/buildah:v1.34.0'
- &go_image 'docker.io/library/golang:1.21.7-bookworm'
- &base_image 'gcr.io/distroless/static-debian12:debug-nonroot'
## value list depends on base image
## ref: https://github.com/GoogleContainerTools/distroless#debian-12
- &target_platforms 'linux/amd64,linux/arm,linux/arm64,linux/ppc64le,linux/s390x'
## kind of fixup (remove in near future)
## ref: https://github.com/woodpecker-ci/plugin-git/releases
clone:
git:
image: woodpeckerci/plugin-git:2.5.0
## NB: ${variable} expressions are subject to pre-processing.
## ref: https://woodpecker-ci.org/docs/usage/environment
steps:
- name: build-all
image: *go_image
environment:
TARGET_PLATFORMS: *target_platforms
VERSION: *version
##
GOPROXY: 'https://nexus.krd.sh/repository/proxy_go,direct'
GOSUMDB: 'sum.golang.org https://nexus.krd.sh/repository/proxy_sum.golang.org'
GOPRIVATE: '*.krd.sh'
GOMAXPROCS: "2"
MALLOC_ARENA_MAX: "4"
commands:
- .ci/build-all.sh
- name: image-all
image: *buildah_image
privileged: true
environment:
TARGET_PLATFORMS: *target_platforms
VERSION: *version
BASE_IMAGE: *base_image
##
IMAGE_REGISTRY: *image_registry
IMAGE_NAME: *image_name
BUILDAH_FORMAT: "docker"
MALLOC_ARENA_MAX: "4"
secrets: [ REGISTRY_AUTH ]
commands:
- .ci/image-all.sh
## personal tweaks :)
labels:
network: dmz

61
.woodpecker/.incoming.yml Normal file
View File

@ -0,0 +1,61 @@
when:
event: [ pull_request ]
variables:
- &version '0.0.1'
- &go_image 'docker.io/library/golang:1.21.7-bookworm'
matrix:
## value list depends on base image
## ref: https://github.com/GoogleContainerTools/distroless#debian-12
TARGET_PLATFORM:
- linux/amd64
- linux/arm
- linux/arm64
- linux/ppc64le
- linux/s390x
## kind of fixup (remove in near future)
## ref: https://github.com/woodpecker-ci/plugin-git/releases
clone:
git:
image: woodpeckerci/plugin-git:2.5.0
## NB: ${variable} expressions are subject to pre-processing.
## ref: https://woodpecker-ci.org/docs/usage/environment
steps:
- name: prepare-env
image: *go_image
environment:
VERSION: *version
MALLOC_ARENA_MAX: "4"
commands:
- |
: # setup build env
: "$${VERSION:?}"
.ci/env.sh
- name: build
image: *go_image
environment:
GOPROXY: 'https://nexus.krd.sh/repository/proxy_go,direct'
GOSUMDB: 'sum.golang.org https://nexus.krd.sh/repository/proxy_sum.golang.org'
GOPRIVATE: '*.krd.sh'
GOMAXPROCS: "2"
MALLOC_ARENA_MAX: "4"
commands:
- |
: # source build env
head -n 40 .build_env
. ./.build_env
: "$${GOOS:?}"
- |
r=0
.ci/build.sh || r=$$?
.ci/build-cleanup.sh
exit $$r
## personal tweaks :)
labels:
network: airgap

38
Dockerfile Normal file
View File

@ -0,0 +1,38 @@
ARG GO_IMAGE=docker.io/library/golang:1.21.7-bookworm
ARG BASE_IMAGE=gcr.io/distroless/static-debian12:debug-nonroot
## ---
FROM ${GO_IMAGE} as build
SHELL [ "/bin/sh", "-ec" ]
ARG GOPROXY
ARG GOSUMDB
ARG GOPRIVATE
ARG RELMODE
WORKDIR /go/src
COPY . .
ENV GOMAXPROCS=2 \
MALLOC_ARENA_MAX=4
RUN go env | grep -F -e GOPROXY -e GOSUMDB -e GOPRIVATE ; \
make OUTDIR=/go/bin ; \
# cleanup intermediate layer
eval "$(go env | grep -F -e GOCACHE -e GOMODCACHE)" ; \
rm -rf ${GOCACHE} ${GOMODCACHE}
## ---
FROM ${BASE_IMAGE}
COPY --from=build /go/bin/plugin-sonatype-nexus /bin/
ENV GOMAXPROCS=4
CMD [ "/bin/plugin-sonatype-nexus" ]
USER nonroot:nonroot

13
Dockerfile.ci Normal file
View File

@ -0,0 +1,13 @@
ARG TARGET_PLATFORM
ARG BASE_IMAGE
FROM --platform=${TARGET_PLATFORM} ${BASE_IMAGE}
ARG PLATFORM_SUFFIX
COPY /dist/plugin-sonatype-nexus${PLATFORM_SUFFIX} /bin/plugin-sonatype-nexus
ENV GOMAXPROCS=4
CMD [ "/bin/plugin-sonatype-nexus" ]
USER nonroot:nonroot

View File

@ -10,7 +10,8 @@ SHELL :=/bin/sh
BIN := plugin-sonatype-nexus
OUTDIR ?= .
OUTBIN := $(OUTDIR)/$(BIN)
OUTSFX ?=
OUTBIN ?= $(OUTDIR)/$(BIN)$(OUTSFX)
export GO ?= go
export CGO_ENABLED ?= 0
@ -39,6 +40,7 @@ build: $(OUTBIN)
test_git = git -c log.showsignature=false show -s --format=%H:%ct
$(OUTBIN):
@:; \
GO_BUILDFLAGS='$(strip $(GO_BUILDFLAGS))' ; \
if ! $(test_git) >/dev/null 2>&1 ; then \
echo "!!! git information is asbent !!!" >&2 ; \
@ -48,7 +50,8 @@ $(OUTBIN):
$${GO_BUILDFLAGS} \
$(if $(strip $(TAGS)),-tags '$(strip $(TAGS))') \
$(if $(strip $(GO_LDFLAGS)),-ldflags '$(strip $(GO_LDFLAGS))') \
$(if $(VERBOSE),-v)
$(if $(VERBOSE),-v) ; \
$(GO) version -m $@
dev-build: GO_BUILDFLAGS := -race $(GO_BUILDFLAGS)
dev-build: CGO_ENABLED := 1