diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 0000000000000..72c8c440e24b2 --- /dev/null +++ b/.github/workflows/pr-build.yml @@ -0,0 +1,53 @@ +name: PR Build + +on: # yamllint disable-line rule:truthy + pull_request: + branches: + - "eve-kernel-riscv64-v6.1.38-generic" + paths-ignore: + - ".github/**" + +concurrency: + group: pr-build-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + runs-on: [runner-xl, Linux] + + steps: + - name: Set sanitized branch name + id: branch-setter + run: | + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + SAFE_BRANCH="${BRANCH_NAME//\//-}" + echo "SAFE_BRANCH=$SAFE_BRANCH" >> $GITHUB_ENV + - name: Checkout PR code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 1 + + - name: Build kernel + run: | + make -f Makefile.eve \ + BRANCH=$SAFE_BRANCH \ + kernel-gcc + + - name: Clean + if: always() + run: | + make -f Makefile.eve \ + BRANCH=$SAFE_BRANCH \ + clean-gcc + if docker ps -q -f name=linuxkit-builder | grep -q .; then + echo "=== BuildKit disk usage before prune ===" + docker exec linuxkit-builder buildctl du | tail -n 2 + echo "=== Reclaiming ===" + docker exec linuxkit-builder buildctl prune --keep-storage "${BUILDKIT_KEEP_STORAGE_MB:-32000}" | tail -n 1 + echo "=== BuildKit disk usage after prune ===" + docker exec linuxkit-builder buildctl du | tail -n 2 + else + echo "linuxkit-builder container not running; skipping BuildKit cleanup." + fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f8873eeb01f4d..9e95839ca3a3a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,41 +1,62 @@ -name: eve-kernel build +name: Building and pushing Eve kernel images on: - workflow_dispatch: - pull_request_review: - types: [ submitted ] - push: - branches: - - "eve-kernel-riscv64-v6.1.38-generic" -env: - branch_name: "refs/heads/eve-kernel-riscv64-v6.1.38-generic" + push: + branches: + - "eve-kernel-riscv64-v6.1.38-generic" concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: main-build-${{ github.ref }} + cancel-in-progress: true jobs: - packages: - runs-on: self-hosted - if: ${{ github.event.review.state == 'approved' }} || github.ref == env.branch_name - steps: - - name: Get eve-kernel - uses: actions/checkout@v3 - with: - ref: ${{ github.head_ref }} - - - name: Build eve-kernel-riscv64 - run: | - make -f Makefile.eve BRANCH?=${GITHUB_REF##*/} kernel-gcc - - - name: Log in to Docker Hub - if: ${{ github.ref == env.branch_name }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.RELEASE_DOCKERHUB_ACCOUNT }} - password: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }} - - - name: Push eve-kernel-riscv64-v6.1.38-generic if PR approved or pushed - if: ${{ github.ref == env.branch_name }} - run: | - make -f Makefile.eve BRANCH?=${GITHUB_REF##*/} push-gcc + build: + runs-on: [runner-xl, Linux] + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.ref }} + fetch-depth: 1 + + - name: Login to Docker Hub (pull) + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + with: + username: ${{ secrets.DOCKERHUB_PULL_USER }} + password: ${{ secrets.DOCKERHUB_PULL_TOKEN }} + + - name: Build kernel from ${{ github.ref_name }} + run: | + make -f Makefile.eve \ + BRANCH=${{ github.ref_name }} \ + kernel-gcc + + - name: Login to Docker Hub (push) + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + with: + username: ${{ secrets.RELEASE_DOCKERHUB_ACCOUNT }} + password: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }} + + - name: Push from ${{ github.ref_name }} + run: | + make -f Makefile.eve \ + BRANCH=${{ github.ref_name }} \ + push-gcc + + - name: Clean + if: always() + run: | + make -f Makefile.eve \ + BRANCH=${{ github.ref_name }} \ + clean-gcc + if docker ps -q -f name=linuxkit-builder | grep -q .; then + echo "=== BuildKit disk usage before prune ===" + docker exec linuxkit-builder buildctl du | tail -n 2 + echo "=== Reclaiming ===" + docker exec linuxkit-builder buildctl prune --keep-storage "${BUILDKIT_KEEP_STORAGE_MB:-32000}" | tail -n 1 + echo "=== BuildKit disk usage after prune ===" + docker exec linuxkit-builder buildctl du | tail -n 2 + else + echo "linuxkit-builder container not running; skipping BuildKit cleanup." + fi diff --git a/Makefile.eve b/Makefile.eve index 16f440def4d88..56488e2cbf238 100644 --- a/Makefile.eve +++ b/Makefile.eve @@ -9,12 +9,29 @@ BUILD_USER:=$(shell id -un) IMAGE_REPOSITORY?=lfedge/eve-kernel -LINUXKIT_VERSION=58c36c9eb0c32acf66ae7877d18a9ad24d59d73e -GOBIN=/tmp/linuxkit-$(LINUXKIT_VERSION) -LK=$(GOBIN)/linuxkit - -BUILD_KIT_VERSION=v0.12.5 -BUILD_KIT_BUILDER=eve-kernel-builder-$(BUILD_KIT_VERSION) +HOSTARCH:=$(subst aarch64,arm64,$(subst x86_64,amd64,$(shell uname -m))) +UNAME_OS_LCASE:=$(shell uname -s | tr '[A-Z]' '[a-z]') + +# linuxkit version. This **must** be a published semver version so it can be +# downloaded already compiled from the release page at +# https://github.com/linuxkit/linuxkit/releases +LINUXKIT_VERSION ?= v1.8.1 +LINUXKIT_SOURCE ?= https://github.com/linuxkit/linuxkit + +# Set LINUXKIT_GIT_URL to build linuxkit from a pinned commit instead of +# downloading a release binary. LINUXKIT_GIT_REF must be a commit hash +# (reproducible, no network call at parse time). +# Update the hash by running: git ls-remote https://github.com/linuxkit/linuxkit master +# Leave LINUXKIT_GIT_URL unset (default) to use the release binary. +LINUXKIT_GIT_URL ?= https://github.com/linuxkit/linuxkit +LINUXKIT_GIT_REF ?= 3bf33c3a11fc20b459195294a7d8980cbca4195b + +ifneq ($(LINUXKIT_GIT_URL),) +_LK_VERSION := $(shell printf '%s' '$(LINUXKIT_GIT_REF)' | cut -c1-12) +LK := /tmp/linuxkit-$(_LK_VERSION) +else +LK := /tmp/linuxkit-$(LINUXKIT_VERSION) +endif SOURCE_DATE_EPOCH=$(shell git log -1 --format=%ct) BRANCH=eve-kernel-$(ARCHITECTURE)-$(KERNEL_TAG)-$(EVE_FLAVOR) @@ -50,30 +67,42 @@ help: Makefile @echo " clean: remove generated files" @echo -.PHONY: ensure-builder -ensure-builder: - docker buildx inspect $(BUILD_KIT_BUILDER) 2>/dev/null || \ - docker buildx create --name $(BUILD_KIT_BUILDER) \ - --driver docker-container --bootstrap --driver-opt=image=moby/buildkit:$(BUILD_KIT_VERSION) - .PHONY: linuxkit linuxkit: $(LK) + +ifneq ($(LINUXKIT_GIT_URL),) +# ── Case 1: build from pinned commit ───────────────────────────────────────── +# The hash is used as the binary name — make skips the recipe if already built. $(LK): - GOBIN=$(GOBIN) go install github.com/linuxkit/linuxkit/src/cmd/linuxkit@$(LINUXKIT_VERSION) + @echo "Building linuxkit from $(LINUXKIT_GIT_URL) at $(LINUXKIT_GIT_REF)" + @tmp=$$(mktemp -d) && \ + git clone --filter=blob:none $(LINUXKIT_GIT_URL) $$tmp && \ + git -C $$tmp checkout $(LINUXKIT_GIT_REF) && \ + $(MAKE) -C $$tmp local-build LOCAL_TARGET=$(abspath $@) && \ + rm -rf $$tmp +else +# ── Case 2: download upstream release binary ────────────────────────────────── +$(LK): + @echo "Downloading linuxkit release $(LINUXKIT_VERSION)" + curl -fsSL -o $@ $(LINUXKIT_SOURCE)/releases/download/$(LINUXKIT_VERSION)/linuxkit-$(UNAME_OS_LCASE)-$(HOSTARCH) && chmod +x $@ +endif -KERNEL_OCI_FILE:=$(shell mktemp -u)-kernel.tar +KERNEL_BUILD_ARGS_FILE := $(shell mktemp -u)-kernel-build-args -kernel-build-%: Makefile.eve linuxkit | ensure-builder +kernel-build-%: Makefile.eve $(LK) @echo "Building kernel version $(BRANCH):$(VERSION)-$* with compiler $*" - docker buildx build \ - --builder=$(BUILD_KIT_BUILDER) \ - --build-arg="SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH)" \ - --build-arg="KBUILD_BUILD_TIMESTAMP=$(KBUILD_BUILD_TIMESTAMP)" \ - --build-arg="LOCALVERSION=$(VERSION)$(DIRTY)" \ - --platform $(PLATFORM) -t $(IMAGE_REPOSITORY):$(BRANCH)-$(VERSION)$(DIRTY)-$* \ - --sbom=true --output=type=oci,dest=$(KERNEL_OCI_FILE) -f Dockerfile.$* . - $(LK) cache import $(KERNEL_OCI_FILE) - rm -f $(KERNEL_OCI_FILE) + @printf 'SOURCE_DATE_EPOCH=%s\nKBUILD_BUILD_TIMESTAMP=%s\nLOCALVERSION=%s\n' \ + '$(SOURCE_DATE_EPOCH)' '$(KBUILD_BUILD_TIMESTAMP)' \ + '$(VERSION)$(DIRTY)' \ + > $(KERNEL_BUILD_ARGS_FILE) + $(LK) pkg build \ + --force \ + --dockerfile Dockerfile.$* \ + --platforms linux/$(ARCHITECTURE) \ + --tag $(BRANCH)-$(VERSION)$(DIRTY)-$* \ + --build-arg-file $(KERNEL_BUILD_ARGS_FILE) \ + . + @rm -f $(KERNEL_BUILD_ARGS_FILE) # we need these intermediate targets to make .PHONY work for pattern rules @@ -83,8 +112,10 @@ docker-tag-gcc: docker-tag-generate-gcc docker-tag-clang: docker-tag-generate-clang push-gcc: push-image-gcc push-clang: push-image-clang +clean-gcc: clean-image-gcc +clean-clang: clean-image-clang -.PHONY: kernel-gcc kernel-clang docker-tag-gcc docker-tag-clang push-gcc push-clang +.PHONY: kernel-gcc kernel-clang docker-tag-gcc docker-tag-clang push-gcc push-clang clean-gcc clean-clang docker-tag-generate-%: @echo "docker.io/$(IMAGE_REPOSITORY):$(BRANCH)-$(VERSION)$(DIRTY)-$*" @@ -93,6 +124,10 @@ push-image-%: $(if $(DIRTY), $(error "Not pushing since the repo is dirty")) $(LK) cache push $(IMAGE_REPOSITORY):$(BRANCH)-$(VERSION)-$* +clean-image-%: + $(LK) cache rm $(IMAGE_REPOSITORY):$(BRANCH)-$(VERSION)$(DIRTY)-$* 2>/dev/null || true + docker rmi $(IMAGE_REPOSITORY):$(BRANCH)-$(VERSION)$(DIRTY)-$* 2>/dev/null || true + .PHONY: clean clean: - echo "Cleaning" + $(LK) cache clean diff --git a/build.yml b/build.yml new file mode 100644 index 0000000000000..5d98437d6da61 --- /dev/null +++ b/build.yml @@ -0,0 +1,3 @@ +org: lfedge +image: eve-kernel +network: yes