Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Configuration for GitHub's automatic release notes.
#
# Used by `gh release create --generate-notes` and by the "Generate release
# notes" button in the UI. Categories are matched in order, so the first match
# wins — which is why `breaking` sits at the top.
#
# Kept identical across the five kube-workspaces repositories so a reader moving
# between them sees the same structure. If you change it here, change it
# everywhere (scripts/check-release-config.sh in the deploy repo enforces this).
changelog:
exclude:
labels:
- duplicate
- invalid
- wontfix
- question

categories:
- title: ⚠️ Breaking changes
labels:
- breaking

- title: 🔒 Security
labels:
- security

- title: ✨ Features
labels:
- enhancement
- feature

- title: 🐛 Fixes
labels:
- bug

- title: 📚 Documentation
labels:
- documentation

- title: 🔧 CI and tooling
labels:
- ci
- chore

- title: ⬆️ Dependencies
labels:
- dependencies

# Anything unlabelled still appears, rather than being silently dropped.
- title: Other changes
labels:
- "*"
5 changes: 5 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ jobs:
# runners. Buildx was already set up; the platforms list was simply
# never passed.
platforms: linux/amd64,linux/arm64
# Compiled into the binary, so a running pod can report what it is.
build-args: |
VERSION=${{ steps.meta.outputs.version }}
COMMIT=${{ github.sha }}
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
106 changes: 106 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Release

# Cut a release: tag the commit, generate notes, publish.
#
# Run from the Actions tab with the version to release. Tagging triggers the
# Docker workflow, which publishes the versioned image.
#
# Release the four component repositories BEFORE kube-workspaces/deploy: the
# chart's appVersion pins these images and must name ones that already exist.
# See https://github.com/kube-workspaces/deploy/blob/main/docs/releasing.md

on:
workflow_dispatch:
inputs:
version:
description: 'Version to release, e.g. v0.3.0'
type: string
required: true
dry_run:
description: 'Print the notes without tagging or publishing'
type: boolean
default: true

permissions:
contents: write

jobs:
release:
name: Release ${{ inputs.version }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
# Full history: the notes are generated from the commit range since the
# previous tag.
fetch-depth: 0

- name: Validate the version
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if ! printf '%s' "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
echo "::error::'$VERSION' is not a vX.Y.Z version"
exit 1
fi
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "::error::tag $VERSION already exists"
exit 1
fi

# The generator lives in the deploy repo so all five repositories classify
# commits the same way.
- name: Fetch the release-notes generator
run: |
curl -fsSLo /tmp/release-notes.sh \
https://raw.githubusercontent.com/kube-workspaces/deploy/main/scripts/release-notes.sh
chmod +x /tmp/release-notes.sh

- name: Generate release notes
id: notes
run: |
set -euo pipefail
/tmp/release-notes.sh \
--repo "${GITHUB_REPOSITORY##*/}" \
--from "$(git describe --tags --abbrev=0)" \
--to HEAD > /tmp/preamble.md
cat /tmp/preamble.md
{
echo 'body<<RELEASE_NOTES_EOF'
cat /tmp/preamble.md
echo 'RELEASE_NOTES_EOF'
} >> "$GITHUB_OUTPUT"

- name: Summary
run: |
{
echo "### Release notes preview for ${{ inputs.version }}"
echo
cat /tmp/preamble.md
} >> "$GITHUB_STEP_SUMMARY"

- name: Create the tag and release
if: ${{ !inputs.dry_run }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
git config user.name 'github-actions[bot]'
git config user.email 'github-actions[bot]@users.noreply.github.com'
git tag -a "$VERSION" -m "$VERSION"
git push origin "$VERSION"

# --generate-notes appends the categorised commit list, grouped per
# .github/release.yml, beneath our preamble.
gh release create "$VERSION" \
--title "$VERSION" \
--notes "${{ steps.notes.outputs.body }}" \
--generate-notes \
--verify-tag

- name: Dry run notice
if: ${{ inputs.dry_run }}
run: |
echo "::notice::dry run — nothing was tagged or published. Re-run with dry_run=false to release."
11 changes: 10 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
ARG TARGETOS
ARG TARGETARCH

# Build information, surfaced by --version, the startup log and /version.
ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown

WORKDIR /workspace
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
go build -a -o manager ./cmd/main.go
go build -a -ldflags "\
-X main.version=${VERSION} \
-X main.commit=${COMMIT} \
-X main.buildDate=${BUILD_DATE}" \
-o manager ./cmd/main.go

FROM gcr.io/distroless/static:nonroot
LABEL org.opencontainers.image.source="https://github.com/kube-workspaces/controller"
Expand Down
36 changes: 36 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ package main
import (
"crypto/tls"
"flag"
"fmt"
"os"
"path/filepath"

// Aliased: the k8s apimachinery "runtime" is already imported below.
goruntime "runtime"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
Expand Down Expand Up @@ -55,6 +59,25 @@ func init() {
}

// nolint:gocyclo
// Build information, injected at link time:
//
// go build -ldflags "-X main.version=v1.2.3 -X main.commit=abc1234 -X main.buildDate=..."
//
// runtime/debug.ReadBuildInfo cannot substitute for this: it reports "(devel)"
// for a build that is not driven by `go install module@version`, which is the
// case for the container build.
var (
version = "dev"
commit = "unknown"
buildDate = "unknown"
)

// versionString renders the build information for logs and the -version flag.
func versionString() string {
return fmt.Sprintf("%s (commit %s, built %s, %s/%s, %s)",
version, commit, buildDate, goruntime.GOOS, goruntime.GOARCH, goruntime.Version())
}

func main() {
var metricsAddr string
var metricsCertPath, metricsCertName, metricsCertKey string
Expand Down Expand Up @@ -85,10 +108,23 @@ func main() {
Development: true,
}
opts.BindFlags(flag.CommandLine)
showVersion := flag.Bool("version", false, "print version information and exit")
flag.Parse()

if *showVersion {
fmt.Println(versionString())
return
}

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

// Log the build up front, so a pod can be identified from its logs alone
// without inspecting the image digest.
setupLog.Info("starting kube-workspaces-controller",
"version", version, "commit", commit, "buildDate", buildDate,
"go", goruntime.Version(),
"platform", fmt.Sprintf("%s/%s", goruntime.GOOS, goruntime.GOARCH))

// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
Expand Down
Loading