diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ed2dfea --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Docs: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# These files will be ignore by Docker for COPY and ADD commands when creating a build context +# In other words, if a file should not be inside of the Docker container it should be +# added to the list, otherwise, it will invalidate cache layers and have to rebuild +# all layers after a COPY command +.git +.github +Dockerfile +.dockerignore +*.md \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..abfabc9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,61 @@ +name: "build" +on: + pull_request: + types: + - opened + - synchronize + - reopened + +jobs: + docker-build: + name: Build & publish Docker images + runs-on: ubuntu-latest + permissions: + packages: write + strategy: + matrix: + target: + - name: builder + image: action-release-builder-image + - name: app + image: action-release-image + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Extract docker tag + run: | + TAG=$(yq '... | select(has("uses") and .uses | test("docker://ghcr.io/getsentry/action-release-image:.*")) | .uses' action.yml | awk -F':' '{print $3}') + echo "DOCKER_TAG=$TAG" >> $GITHUB_ENV + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # BUILDKIT_INLINE_CACHE creates the image in such a way that you can + # then use --cache-from (think of a remote cache) + # This feature is allowed thanks to using the buildx plugin + # + # There's a COPY command in the builder stage that can easily invalidate the cache + # If you notice, please add more exceptions to .dockerignore since we loose the value + # of using --cache-from on the app stage + - name: Build and push + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm64 + push: true + tags: ghcr.io/${{ github.repository_owner }}/${{ matrix.target.image }}:${{ env.DOCKER_TAG }} + cache-from: ghcr.io/${{ github.repository_owner }}/${{ matrix.target.image }}:master + target: ${{ matrix.target.name }} + build-args: BUILDKIT_INLINE_CACHE=1 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2924565..0868f2f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Prepare Release +name: "Action: Prepare Release" on: workflow_dispatch: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a764712 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# The multi stage set up *saves* up image size by avoiding the dev dependencies +# required to produce dist/ +FROM node:18-alpine as builder +WORKDIR /app +# This layer will invalidate upon new dependencies +COPY package.json yarn.lock ./ +RUN export YARN_CACHE_FOLDER="$(mktemp -d)" \ + && yarn install --frozen-lockfile --quiet \ + && rm -r "$YARN_CACHE_FOLDER" +# If there's some code changes that causes this layer to +# invalidate but it shouldn't, use .dockerignore to exclude it +COPY . . +RUN yarn build + +FROM node:18-alpine as app +COPY package.json yarn.lock /action-release/ +# On the builder image, we install both types of dependencies rather than +# just the production ones. This generates /action-release/node_modules +RUN export YARN_CACHE_FOLDER="$(mktemp -d)" \ + && cd /action-release \ + && yarn install --frozen-lockfile --production --quiet \ + && rm -r "$YARN_CACHE_FOLDER" + +# Copy the artifacts from `yarn build` +COPY --from=builder /app/dist /action-release/dist/ +RUN chmod +x /action-release/dist/index.js + +RUN printf '[safe]\n directory = *\n' > /etc/gitconfig + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/action.yml b/action.yml index 26331d4..f000f25 100644 --- a/action.yml +++ b/action.yml @@ -58,20 +58,47 @@ inputs: runs: using: 'composite' steps: +# - name: Extract tag to use for docker image +# if: runner.os == 'Linux' +# shell: bash +# run: | +# GIT_REF="${{ github.action_ref }}" +# if [[ "$GIT_REF" == refs/tags/* ]]; then +# DOCKER_TAG=${REF#refs/tags/} +# elif [[ "$GIT_REF" == refs/heads/* ]]; then +# DOCKER_TAG=${GIT_REF#refs/heads/} +# else +# DOCKER_TAG="master" +# fi +# echo "DOCKER_TAG=$DOCKER_TAG" >> $GITHUB_ENV + + # For actions running on a linux runner, we use a docker + # approach as it's faster and encapsulates everything needed + # to run the action. + - name: Run docker image + if: runner.os != 'macOS' && runner.os != 'Windows' + uses: docker://ghcr.io/getsentry/action-release-image:ab/multiarch-docker + + # For actions running on macos or windows runners, we use a composite + # action approach so it allows us to install the arch specific sentry-cli + # that's needed for the runner. This is slower and runners require to have + # node and npm available. - name: Mark GitHub workspace a safe directory in git - if: ${{ inputs.disable_safe_directory != 'true' }} + if: ${{ (runner.os == 'macOS' || runner.os == 'Windows') && inputs.disable_safe_directory != 'true' }} shell: bash run: | git config --global --add safe.directory "$GITHUB_WORKSPACE" - - name: Get node version + - name: Get node and npm versions + if: runner.os == 'macOS' || runner.os == 'Windows' shell: bash run: | echo "NODE_VERSION=$(node -v 2>/dev/null || echo '')" >> $GITHUB_ENV + echo "NPM_VERSION=$(npm -v 2>/dev/null || echo '')" >> $GITHUB_ENV - name: Setup node # Only install node if there isn't one already - if: env.NODE_VERSION == '' + if: ${{ (runner.os == 'macOS' || runner.os == 'Windows') && (env.NODE_VERSION == '' || env.NPM_VERSION == '') }} uses: actions/setup-node@v4 with: # setup-node doesn't allow absolute paths, so we can't @@ -80,11 +107,13 @@ runs: node-version: 18.17.0 - name: Install Sentry CLI v2 + if: runner.os == 'macOS' || runner.os == 'Windows' shell: bash - run: npm install --save-dev --no-package-lock @sentry/cli@^2.4 + run: npm install --no-package-lock @sentry/cli@^2.4 working-directory: ${{ github.action_path }} - name: Run Release Action + if: runner.os == 'macOS' || runner.os == 'Windows' env: # Composite actions don't pass the outer action's inputs # down into these steps, so we have to replicate all inputs to be accessible diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..1451700 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/sh -l +node /action-release/dist/index.js \ No newline at end of file diff --git a/package.json b/package.json index 1ef25cb..dc3cd82 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,10 @@ "license": "MIT", "dependencies": { "@actions/core": "^1.11.1", - "@sentry/node": "^8.54.0" + "@sentry/node": "^8.54.0", + "@sentry/cli": "^2.41.1" }, "devDependencies": { - "@sentry/cli": "^2.41.1", "@types/jest": "^29.5.6", "@types/node": "^20.8.9", "@typescript-eslint/parser": "^6.9.0", diff --git a/scripts/craft-pre-release.sh b/scripts/craft-pre-release.sh index d5ee22b..a42ca47 100644 --- a/scripts/craft-pre-release.sh +++ b/scripts/craft-pre-release.sh @@ -16,3 +16,6 @@ npm version "${NEW_VERSION}" # The build output contains the package.json so we need to # rebuild to ensure it's reflected after bumping the version yarn install && yarn build + +# Update the docker tag in action.yml +./scripts/set-docker-tag $NEW_VERSION diff --git a/scripts/set-branch-docker-tag.sh b/scripts/set-branch-docker-tag.sh new file mode 100755 index 0000000..e459ae3 --- /dev/null +++ b/scripts/set-branch-docker-tag.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -eux + +BRANCH=$(git rev-parse --abbrev-ref HEAD) + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $SCRIPT_DIR + +./set-docker-tag.sh $BRANCH diff --git a/scripts/set-docker-tag.sh b/scripts/set-docker-tag.sh new file mode 100755 index 0000000..86ebe7a --- /dev/null +++ b/scripts/set-docker-tag.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -eux + +DOCKER_REGISTRY_IMAGE="docker://ghcr.io/getsentry/action-release-image" +TAG="${1}" + +# Move to the project root +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $SCRIPT_DIR/.. + +# We don't want the backup but this is the only way to make this +# work on macos as well +sed -i.bak -e "s|\($DOCKER_REGISTRY_IMAGE:\)[^']*|\1$TAG|" action.yml && rm -f action.yml.bak