From 1ebd7f8099656f954ff3b770defa59f0a6180f3e Mon Sep 17 00:00:00 2001 From: Gerald Pinder Date: Sat, 4 Jan 2025 10:45:32 -0500 Subject: [PATCH] feat: Support arm64 and amd64 builds of nushell --- .github/workflows/build.yml | 3 ++ Containerfile | 10 +++-- build.nu | 79 ++++++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 19 deletions(-) mode change 100644 => 100755 build.nu diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0be5bec..d7b95f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,9 @@ jobs: - uses: docker/setup-buildx-action@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: diff --git a/Containerfile b/Containerfile index 7681194..2f5de7d 100644 --- a/Containerfile +++ b/Containerfile @@ -1,16 +1,18 @@ -FROM ubuntu:20.04 as cached +FROM ubuntu:22.04 as cached RUN apt-get update && apt-get install -y wget FROM cached as build -ARG URL=https://github.com/nushell/nushell/releases/download/0.98.0/nu-0.98.0-x86_64-unknown-linux-gnu.tar.gz +ARG VERSION=0.99.1 +ARG DOWNLOAD_ARCH=x86_64 +ARG URL=https://github.com/nushell/nushell/releases/download/${VERSION}/nu-${VERSION}-${DOWNLOAD_ARCH}-unknown-linux-musl.tar.gz -RUN wget -O /tmp/archive.tar.gz "$URL" && \ +RUN wget -q -O /tmp/archive.tar.gz "$URL" && \ mkdir /tmp/extract/ && \ tar -xzf /tmp/archive.tar.gz -C /tmp/extract/ && \ mv /tmp/extract/nu* /nu/ FROM scratch -COPY --from=build /nu/ /nu/ \ No newline at end of file +COPY --from=build /nu/ /nu/ diff --git a/build.nu b/build.nu old mode 100644 new mode 100755 index 3c5410e..999f86f --- a/build.nu +++ b/build.nu @@ -4,12 +4,31 @@ # version to be tagged with `default` and used by BlueBuild modules const DEFAULT_VERSION = "0.99.1" +# architectures to build and the corresponding download arch string +const BUILD_ARCHS = [ + { + docker: "linux/amd64", + download: "x86_64", + }, + { + docker: "linux/arm64", + download: "aarch64", + } +] + print $"(ansi green_bold)Gathering images" let images = http get https://api.github.com/repos/nushell/nushell/releases | enumerate | each { |arrayEl| let release = $arrayEl.item - let url = ($release.assets | where name ends-with "x86_64-unknown-linux-musl.tar.gz").browser_download_url.0 + if not ($BUILD_ARCHS | all {|arch| + ($release.assets | any {|asset| + $asset.name | str contains $"($arch.download)-unknown-linux-musl" + }) + }) { + return + } + let version = $release.name let tags = ( @@ -32,7 +51,6 @@ let images = http get https://api.github.com/repos/nushell/nushell/releases | en print $"(ansi cyan)Found version & generated tags:(ansi reset) ($tags | str join ' ')" { - url: $url version: $version tags: $tags } @@ -41,22 +59,53 @@ let images = http get https://api.github.com/repos/nushell/nushell/releases | en print $"(ansi green_bold)Starting image build(ansi reset)" $images | each { |img| + let base_image = $"($env.REGISTRY)/nushell-image" - print $"(ansi cyan)Building image for version:(ansi reset) ($img.version)" - (docker build . - -f ./Containerfile - ...($img.tags | each { |tag| ["-t", $"($env.REGISTRY)/nushell-image:($tag)"] } | flatten) # generate and spread list of tags - --build-arg $"URL=($img.url)") + $BUILD_ARCHS | each { |arch| + print $"(ansi cyan)Building image for version:(ansi reset) ($img.version)" -} + let tag = $"($base_image):($img.version)-($arch.download)" + + try { + (docker build . + -f ./Containerfile + --platform $arch.docker + -t $tag + --build-arg $"VERSION=($img.version)" + --build-arg $"DOWNLOAD_ARCH=($arch.download)") + + print $"(ansi cyan)Pushing image for platform ($arch.download) and version ($img.version):(ansi reset) ($tag)" + docker push $tag + } catch { + print $"(ansi red_bold)Failed to build image(ansi reset) ($tag)" + exit 1 + } + } + + $img.tags | each { |tag| + let final_image = $"($base_image):($tag)" + + try { + print $"(ansi cyan)Creating multi-platform manifest:(ansi reset) ($final_image)" + (docker manifest create $final_image + ...($BUILD_ARCHS | each { |arch| + ["--amend", $"($base_image):($img.version)-($arch.download)"] + } | flatten)) + + print $"(ansi cyan)Pushing multi-platform manifest:(ansi reset) ($final_image)" + docker manifest push $final_image -print $"(ansi cyan)Pushing images:(ansi reset)" -let digest = ( - docker push --all-tags $"($env.REGISTRY)/nushell-image" - | split row "\n" | last | split row " " | get 2 # parse push output to get digest for signing -) + (docker manifest inspect $final_image | from json).manifests | each { |manifest| + let digest_image = $"($base_image)@($manifest.digest)" -print $"(ansi cyan)Signing image:(ansi reset) ($env.REGISTRY)/nushell-image@($digest)" -cosign sign -y --key env://COSIGN_PRIVATE_KEY $"($env.REGISTRY)/nushell-image@($digest)" + print $"(ansi cyan)Signing image:(ansi reset) ($digest_image)" + cosign sign -y --key env://COSIGN_PRIVATE_KEY $digest_image + } + } catch { + print $"(ansi red_bold)Failed to create and sign manifest(ansi reset) ($final_image)" + exit 1 + } + } +} print $"(ansi green_bold)DONE!(ansi reset)"