diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..febc574 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,98 @@ +name: Release + +on: + pull_request: + types: [closed] + +permissions: {} + +jobs: + release: + if: >- + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'release') + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + env: + IMAGE: ghcr.io/${{ github.repository }} + steps: + - name: Create GitHub App token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + id: app-token + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + permission-contents: write + + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Extract version + id: version + run: | + VERSION=$(cat VERSION) + if ! echo "${VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "::error::Invalid version format: ${VERSION}" + exit 1 + fi + echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" + echo "tag=v${VERSION}" >> "${GITHUB_OUTPUT}" + + - name: Create and push tag + env: + TAG: ${{ steps.version.outputs.tag }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + if git rev-parse "${TAG}" >/dev/null 2>&1; then + echo "::error::Tag ${TAG} already exists" + exit 1 + fi + git tag -a -m "Release ${TAG}" "${TAG}" + git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push origin "${TAG}" + git remote set-url origin "https://github.com/${GITHUB_REPOSITORY}.git" + + - name: Set up Go + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: go.mod + cache: true # zizmor: ignore[cache-poisoning] + + - name: Build and push container image + env: + TAG: ${{ steps.version.outputs.tag }} + ACTOR: ${{ github.actor }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + make buildimg IMG="${IMAGE}:${TAG}" + podman login -u "${ACTOR}" -p "${GH_TOKEN}" ghcr.io + podman push "${IMAGE}:${TAG}" + + - name: Build install manifest + env: + TAG: ${{ steps.version.outputs.tag }} + run: make release-manifest IMG="${IMAGE}:${TAG}" + + - name: Create release + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + TAG: ${{ steps.version.outputs.tag }} + run: | + { + printf '## Installation\n\n' + printf '```bash\n' + printf 'kubectl apply -f https://github.com/%s/releases/download/%s/install.yaml\n' \ + "${GITHUB_REPOSITORY}" "${TAG}" + printf '```\n' + } > notes.md + gh release create "${TAG}" \ + --title "Release ${TAG}" \ + --notes-file notes.md \ + --generate-notes \ + --draft \ + install.yaml diff --git a/Containerfile b/Containerfile index e6a92ad..a0d6f17 100644 --- a/Containerfile +++ b/Containerfile @@ -4,6 +4,8 @@ RUN --mount=type=cache,id=dnf,target=/var/cache/libdnf5 \ dnf install ${DNF_FLAGS} golang FROM buildroot as builder +ARG VERSION=dev +ARG GIT_COMMIT=unknown WORKDIR /workspace COPY go.mod go.sum ./ RUN --mount=type=cache,id=gomod,target=/root/go/pkg/mod \ @@ -11,8 +13,9 @@ RUN --mount=type=cache,id=gomod,target=/root/go/pkg/mod \ COPY . . RUN --mount=type=cache,id=gomod,target=/root/go/pkg/mod \ --mount=type=cache,id=gobuild,target=/root/.cache/go-build \ - go build -o manager ./cmd/controller/ && \ - go build -o daemon ./cmd/daemon/ + LDFLAGS="-X github.com/bootc-dev/bootc-operator/internal/version.Version=${VERSION} -X github.com/bootc-dev/bootc-operator/internal/version.GitCommit=${GIT_COMMIT}" && \ + go build -ldflags "${LDFLAGS}" -o manager ./cmd/controller/ && \ + go build -ldflags "${LDFLAGS}" -o daemon ./cmd/daemon/ FROM quay.io/fedora/fedora-minimal:44 COPY --from=builder /workspace/manager /workspace/daemon /usr/local/bin/ diff --git a/Makefile b/Makefile index d608e5d..23b111c 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ CONTAINER_TOOL ?= podman BINK_CLUSTER_NAME ?= e2e KUBECONFIG_BINK ?= ./kubeconfig-$(BINK_CLUSTER_NAME) ARTIFACTS ?= $(abspath _output/logs) +VERSION ?= $(shell git describe --tags --always --dirty) +GIT_COMMIT ?= $(shell git rev-parse --short HEAD) +LDFLAGS := -X github.com/bootc-dev/bootc-operator/internal/version.Version=$(VERSION) \ + -X github.com/bootc-dev/bootc-operator/internal/version.GitCommit=$(GIT_COMMIT) DEFAULT_KUBE_MINOR ?= 1.35 BINK_NODE_DISK_IMAGE ?= ghcr.io/bootc-dev/bink/node:v$(DEFAULT_KUBE_MINOR)-fedora-44-disk BINK_LOCAL_REGISTRY_NODE_IMAGE ?= registry.cluster.local:5000/node @@ -105,16 +109,23 @@ build: build-manager build-daemon ## Build all binaries. .PHONY: build-manager build-manager: ## Build manager binary. - go build -o bin/manager ./cmd/controller/ + go build -ldflags '$(LDFLAGS)' -o bin/manager ./cmd/controller/ .PHONY: build-daemon build-daemon: ## Build daemon binary. - go build -o bin/daemon ./cmd/daemon/ + go build -ldflags '$(LDFLAGS)' -o bin/daemon ./cmd/daemon/ .PHONY: buildimg buildimg: ## Build container image. $(CONTAINER_TOOL) build -t $(IMG) . +.PHONY: release-manifest +release-manifest: kustomize yq ## Build install manifest (override IMG to set the image reference). + "$(KUSTOMIZE)" build config/default | \ + "$(YQ)" '(select(.kind == "Deployment") | .spec.template.spec.containers[] | select(.name == "manager")).image = "$(IMG)"' | \ + "$(YQ)" '(select(.kind == "DaemonSet") | .spec.template.spec.containers[] | select(.name == "daemon")).image = "$(IMG)"' \ + > install.yaml + .PHONY: build-update-image build-update-image: ## Build derived node images for update testing and push to bink registry. @printf 'FROM localhost:5000/node:latest\nRUN touch /usr/share/update-marker\n' | \ diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 7b09f39..76699e1 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -18,6 +18,7 @@ import ( bootcv1alpha1 "github.com/bootc-dev/bootc-operator/api/v1alpha1" "github.com/bootc-dev/bootc-operator/internal/controller" "github.com/bootc-dev/bootc-operator/internal/registry" + "github.com/bootc-dev/bootc-operator/internal/version" ) var ( @@ -64,6 +65,16 @@ func main() { ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + setupLog.Info( + "starting", + "component", + "controller", + "version", + version.Version, + "commit", + version.GitCommit, + ) + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, HealthProbeBindAddress: probeAddr, diff --git a/cmd/daemon/main.go b/cmd/daemon/main.go index 84ac526..c4ec121 100644 --- a/cmd/daemon/main.go +++ b/cmd/daemon/main.go @@ -21,6 +21,7 @@ import ( bootcv1alpha1 "github.com/bootc-dev/bootc-operator/api/v1alpha1" "github.com/bootc-dev/bootc-operator/internal/bootc" "github.com/bootc-dev/bootc-operator/internal/daemon" + "github.com/bootc-dev/bootc-operator/internal/version" ) var ( @@ -50,6 +51,16 @@ func main() { ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + setupLog.Info( + "starting", + "component", + "daemon", + "version", + version.Version, + "commit", + version.GitCommit, + ) + nodeName := os.Getenv("NODE_NAME") if nodeName == "" { setupLog.Error( diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..07251d1 --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 + +package version + +var ( + Version = "dev" + GitCommit = "unknown" +)