diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 636bf35..c3687b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,6 +61,7 @@ jobs: strategy: matrix: go-version: [1.21.x] + arch: ["arm64", "amd64"] runs-on: ubuntu-latest permissions: id-token: write @@ -87,9 +88,8 @@ jobs: run: | docker build \ -f docker/pulumi/Dockerfile \ - --platform linux/amd64 \ - -t ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }} \ - -t ${{ env.DOCKER_ORG }}/pulumi:latest \ + --platform linux/${{ matrix.arch }} \ + -t ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} \ --target base \ --build-arg PULUMI_VERSION=${{ env.PULUMI_VERSION }} \ --load \ @@ -98,9 +98,8 @@ jobs: run: | docker build \ -f docker/pulumi/Dockerfile \ - --platform linux/amd64 \ - -t ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot \ - -t ${{ env.DOCKER_ORG }}/pulumi:latest-nonroot \ + --platform linux/${{ matrix.arch }} \ + -t ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-${{ matrix.arch }} \ --target nonroot \ --build-arg PULUMI_VERSION=${{ env.PULUMI_VERSION }} \ --load \ @@ -153,7 +152,7 @@ jobs: --mount type=bind,source=$GOOGLE_APPLICATION_CREDENTIALS,target=/src/creds.json \ --volume /tmp:/src \ --entrypoint /src/pulumi-test-containers \ - ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }} \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} \ -test.timeout=1h -test.v - name: Tests for nonroot variant run: | @@ -177,23 +176,57 @@ jobs: --mount type=bind,source=$GOOGLE_APPLICATION_CREDENTIALS,target=/src/creds.json \ --volume /tmp:/src \ --entrypoint /src/pulumi-test-containers \ - ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-${{ matrix.arch }} \ -test.timeout=1h -test.v - name: Push ${{ env.PULUMI_VERSION }} run: | - docker push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }} - docker push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot - - name: Push latest + docker push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} + docker push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-${{ matrix.arch }} + kitchen-sink-manifests: + name: Kitchen sink image manifests + needs: ["kitchen-sink"] + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ env.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Versioned manifest + run: | + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }} \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-amd64 + docker manifest push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }} + + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-amd64 + docker manifest push ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot + - name: Latest manifest if: ${{ github.event.inputs.tag_latest || github.event_name == 'repository_dispatch' }} + # Manifest lists can't be a source for `docker tag`, so we create an + # additional copy of the previous manifest to tag latest: run: | - docker push ${{ env.DOCKER_ORG }}/pulumi:latest - docker push ${{ env.DOCKER_ORG }}/pulumi:latest-nonroot - + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi:latest \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-amd64 + docker manifest push ${{ env.DOCKER_ORG }}/pulumi:latest + + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi:latest-nonroot \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi:${{ env.PULUMI_VERSION }}-nonroot-amd64 + docker manifest push ${{ env.DOCKER_ORG }}/pulumi:latest-nonroot provider-build-environment: name: Provider Build Environment image strategy: matrix: go-version: [1.21.1] + arch: ["arm64", "amd64"] runs-on: ubuntu-latest permissions: id-token: write @@ -221,8 +254,7 @@ jobs: docker build \ -f docker/pulumi/Dockerfile \ --platform linux/amd64 \ - -t ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }} \ - -t ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:latest \ + -t ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} \ --target build-environment \ --build-arg PULUMI_VERSION=${{ env.PULUMI_VERSION }} \ --load \ @@ -275,13 +307,36 @@ jobs: --mount type=bind,source=$GOOGLE_APPLICATION_CREDENTIALS,target=/src/creds.json \ --volume /tmp:/src \ --entrypoint /src/pulumi-test-containers \ - ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }} \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} \ -test.parallel=1 -test.timeout=1h -test.v - name: Push ${{ env.PULUMI_VERSION }} - run: docker push ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }} - - name: Push latest + run: docker push ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-${{ matrix.arch }} + provider-build-environment-manifests: + name: Provider Build Environment manifests + needs: ["provider-build-environment"] + runs-on: ubuntu-latest + steps: + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ env.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Versioned manifest + run: | + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }} \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-amd64 + - name: Latest manifest if: ${{ github.event.inputs.tag_latest || github.event_name == 'repository_dispatch' }} - run: docker push ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:latest + # Manifest lists can't be a source for `docker tag`, so we create an + # additional copy of the previous manifest to tag latest: + run: | + docker manifest create \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:latest \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-arm64 \ + ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:${{ env.PULUMI_VERSION }}-amd64 + docker manifest push ${{ env.DOCKER_ORG }}/pulumi-provider-build-environment:latest base: name: Base image diff --git a/.github/workflows/sync-ecr.yml b/.github/workflows/sync-ecr.yml index 1d20fa6..de65fdb 100644 --- a/.github/workflows/sync-ecr.yml +++ b/.github/workflows/sync-ecr.yml @@ -49,17 +49,24 @@ jobs: --query 'authorizationData.authorizationToken' | \ tr -d '"' | base64 --decode | cut -d: -f2 | \ docker login -u AWS --password-stdin https://public.ecr.aws - - name: Tag ${{ env.PULUMI_VERSION }} and push to AWS Public ECR + - name: Tag ${{ env.PULUMI_VERSION }}-arm64 and push to AWS Public ECR run: | - docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - docker push public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - - name: Tag latest and push to AWS Public ECR + docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker push public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + - name: Tag ${{ env.PULUMI_VERSION }}-amd64 and push to AWS Public ECR + run: | + docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + docker push public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + - name: Push latest manifest if: ${{ github.event.inputs.tag_latest || github.event_name == 'repository_dispatch' }} run: | - docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} - docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} - docker push public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} + docker manifest create \ + public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} \ + public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 \ + public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker manifest push public.ecr.aws/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} define-debian-matrix: runs-on: ubuntu-latest diff --git a/.github/workflows/sync-ghcr.yml b/.github/workflows/sync-ghcr.yml index 5f7e4dc..4814ca3 100644 --- a/.github/workflows/sync-ghcr.yml +++ b/.github/workflows/sync-ghcr.yml @@ -39,17 +39,24 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Tag ${{ env.PULUMI_VERSION }} and push to GHCR + - name: Tag ${{ env.PULUMI_VERSION }}-arm64 and push to GHCR run: | - docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - docker push ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }} - - name: Tag latest and push to GHCR + docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker push ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + - name: Tag ${{ env.PULUMI_VERSION }}-amd64 and push to GHCR + run: | + docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + docker push ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 + - name: Push latest manifest to GHCR if: ${{ github.event.inputs.tag_latest || github.event_name == 'repository_dispatch' }} run: | - docker pull docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} - docker tag docker.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} - docker push ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} + docker manifest create \ + ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} \ + ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-amd64 \ + ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:${{ env.PULUMI_VERSION }}${{ matrix.suffix }}-arm64 + docker manifest push ghcr.io/${{ env.DOCKER_USERNAME }}/${{ matrix.image }}:latest${{ matrix.suffix }} define-debian-matrix: runs-on: ubuntu-latest diff --git a/docker/pulumi/Dockerfile b/docker/pulumi/Dockerfile index bdea507..5b954f7 100644 --- a/docker/pulumi/Dockerfile +++ b/docker/pulumi/Dockerfile @@ -1,12 +1,17 @@ FROM debian:12 AS base +# These values are passed in by the build system automatically. The options are: arm64, amd64 +# See: https://docs.docker.com/build/building/variables/#pre-defined-build-arguments +ARG TARGETARCH + LABEL "repository"="https://github.com/pulumi/pulumi" LABEL "homepage"="https://pulumi.com" LABEL "maintainer"="Pulumi Team " LABEL org.opencontainers.image.description="The Pulumi CLI, in a Docker container." ENV GOLANG_VERSION 1.21.1 -ENV GOLANG_SHA256 b3075ae1ce5dab85f89bc7905d1632de23ca196bd8336afd93fa97434cfa55ae +ENV GOLANG_AMD64_SHA256 b3075ae1ce5dab85f89bc7905d1632de23ca196bd8336afd93fa97434cfa55ae +ENV GOLANG_ARM64_SHA256 7da1a3936a928fd0b2602ed4f3ef535b8cd1990f1503b8d3e1acc0fa0759c967 # Install base dependencies RUN apt-get update -y && \ @@ -36,11 +41,17 @@ RUN apt-get update -y && \ # Install cloud tools RUN \ + # Setup environment variables for architecture-specific packages + if [ "$TARGETARCH" = "arm64" ]; then \ + AWSCLI_ARCH=aarch64; \ + else \ + AWSCLI_ARCH=x86_64; \ + fi && \ # IAM Authenticator for EKS - curl -fsSLo /usr/bin/aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.28.2/2023-10-17/bin/linux/amd64/aws-iam-authenticator && \ + curl -fsSLo /usr/bin/aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.28.2/2023-10-17/bin/linux/${TARGETARCH}/aws-iam-authenticator && \ chmod +x /usr/bin/aws-iam-authenticator && \ # AWS v2 cli - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \ + curl "https://awscli.amazonaws.com/awscli-exe-linux-${AWSCLI_ARCH}.zip" -o "awscliv2.zip" && \ unzip awscliv2.zip && \ ./aws/install && \ rm -rf aws && \ @@ -49,13 +60,13 @@ RUN \ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \ curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ - echo "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list && \ + echo "deb [arch=${TARGETARCH}] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list && \ echo "deb http://packages.cloud.google.com/apt cloud-sdk-$(lsb_release -cs) main" | tee /etc/apt/sources.list.d/google-cloud-sdk.list && \ KUBE_LATEST=$(curl -L -s https://dl.k8s.io/release/stable.txt | awk 'BEGIN { FS="." } { printf "%s.%s", $1, $2 }') && \ mkdir -p /etc/apt/keyrings && \ curl -fsSL https://pkgs.k8s.io/core:/stable:/${KUBE_LATEST}/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${KUBE_LATEST}/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list && \ - echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure.list && \ + echo "deb [arch=${TARGETARCH}] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/azure.list && \ # Install azure-cli, docker, gcloud, kubectl apt-get update -y && \ apt-get install -y \ @@ -67,7 +78,14 @@ RUN \ rm -rf /var/lib/apt/lists/* # Install Go -RUN curl -fsSLo /tmp/go.tgz https://golang.org/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz && \ +RUN \ + # Setup environment variables for architecture-specific packages + if [ "$TARGETARCH" = "arm64" ]; then \ + GOLANG_SHA256=$GOLANG_ARM64_SHA256; \ + else \ + GOLANG_SHA256=$GOLANG_AMD64_SHA256; \ + fi && \ + curl -fsSLo /tmp/go.tgz https://golang.org/dl/go${GOLANG_VERSION}.linux-${TARGETARCH}.tar.gz && \ echo "${GOLANG_SHA256} /tmp/go.tgz" | sha256sum -c - && \ tar -C /usr/local -xzf /tmp/go.tgz && \ rm /tmp/go.tgz && \ @@ -182,6 +200,8 @@ RUN helm repo add stable https://charts.helm.sh/stable && \ FROM base AS build-environment +ARG TARGETARCH + # https://github.com/pulumi/pulumictl/releases ENV PULUMICTL_VERSION 0.0.32 # https://github.com/golangci/golangci-lint/releases @@ -191,14 +211,21 @@ ENV GORELEASER_VERSION 1.11.4 SHELL ["/bin/bash", "-o", "errexit", "-o", "nounset", "-o", "pipefail", "-c"] -RUN curl \ +RUN \ + # Setup environment variables for architecture-specific packages + if [ "$TARGETARCH" = "arm64" ]; then \ + GORELEASER_ARCH=arm64; \ + else \ + GORELEASER_ARCH=x86_64; \ + fi && \ + curl \ --proto "=https" \ --tlsv1.2 \ --location \ --fail \ --verbose \ --output "pulumictl.tar.gz" \ - "https://github.com/pulumi/pulumictl/releases/download/v${PULUMICTL_VERSION}/pulumictl-v${PULUMICTL_VERSION}-linux-amd64.tar.gz" && \ + "https://github.com/pulumi/pulumictl/releases/download/v${PULUMICTL_VERSION}/pulumictl-v${PULUMICTL_VERSION}-linux-${TARGETARCH}.tar.gz" && \ mkdir pulumictl_extraction && \ tar --extract --gunzip --verbose --directory pulumictl_extraction --file pulumictl.tar.gz && \ mv pulumictl_extraction/pulumictl /usr/local/bin/pulumictl && \ @@ -222,7 +249,7 @@ RUN curl \ --fail \ --verbose \ --output "goreleaser.tar.gz" \ - "https://github.com/goreleaser/goreleaser/releases/download/v${GORELEASER_VERSION}/goreleaser_Linux_x86_64.tar.gz" && \ + "https://github.com/goreleaser/goreleaser/releases/download/v${GORELEASER_VERSION}/goreleaser_Linux_${GORELEASER_ARCH}.tar.gz" && \ mkdir goreleaser_extraction && \ tar --extract --gunzip --verbose --directory goreleaser_extraction --file goreleaser.tar.gz && \ mv goreleaser_extraction/goreleaser /usr/local/bin/goreleaser && \