diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c4c8228 --- /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 diff --git a/.github/actions/setup-docker/action.yml b/.github/actions/setup-docker/action.yml deleted file mode 100644 index c4e1f7d..0000000 --- a/.github/actions/setup-docker/action.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: "Setup Docker" -description: "Use the local Dockerfile to test the action instead of the one on DockerHub" - -runs: - using: "composite" - steps: - - name: Replace image on action.yml - shell: bash - env: - ESC_DOCKER_IMAGE_LINK: 'docker\:\/\/sentryintegrations\/sentry-github-action-release\:latest' - run: | - mv action.yml previous.yml - sed "s/$ESC_DOCKER_IMAGE_LINK/Dockerfile/" previous.yml >> action.yml diff --git a/.github/actions/use-local-dockerfile/action.yml b/.github/actions/use-local-dockerfile/action.yml new file mode 100644 index 0000000..cfb62f4 --- /dev/null +++ b/.github/actions/use-local-dockerfile/action.yml @@ -0,0 +1,12 @@ +name: "Use local Dockerfile" +description: "Use the local Dockerfile to test the action instead of the one on DockerHub" + +runs: + using: "composite" + steps: + - name: Replace image on action.yml + shell: bash + run: | + mv action.yml previous.yml + sed "s|docker://ghcr.io/getsentry/action-release-image:latest|Dockerfile|" previous.yml >> action.yml + grep "image" action.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b38dde..6a0aa02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,18 +5,38 @@ on: - master jobs: - build: + docker-build: + name: Build & pubish Docker images runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} + uses: actions/checkout@v3 - - name: Docker - uses: docker/build-push-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - repository: sentryintegrations/sentry-github-action-release - tags: latest + # 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 Docker builder image + run: | + docker buildx build . \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + -t ghcr.io/getsentry/action-release-builder-image:latest \ + --cache-from ghcr.io/getsentry/action-release-builder-image:latest \ + --target builder + + - name: Build Docker image + run: | + docker buildx build . \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + -t ghcr.io/getsentry/action-release-image:latest \ + --cache-from ghcr.io/getsentry/action-release-image:latest \ + --target app + + - name: Login and publish + run: | + docker login ghcr.io -u $GITHUB_ACTOR --password-stdin <<< ${{ secrets.GITHUB_TOKEN }} + docker push ghcr.io/getsentry/action-release-builder-image:latest + docker push ghcr.io/getsentry/action-release-image:latest \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be69a24..8dbec3e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,17 +4,19 @@ on: push: branches: - master - - 'releases/*' jobs: - mock: # Make sure that the action works on a clean machine without building + mock-release: # Make sure that the action works on a clean machine without building + name: "Build image & mock a release" runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: './.github/actions/setup-docker' + + - uses: './.github/actions/use-local-dockerfile' + - name: Mock creating a Sentry release uses: ./ env: MOCK: true with: - environment: production + environment: production \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 4a3e22f..595f239 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,31 @@ +# The multi stage set up *saves* up image size by avoiding the dev dependencies +# required to produce dist/ FROM node:12-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:12-alpine -COPY --from=builder /app/package.json /app/yarn.lock /action-release/ +FROM node:12-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 +# XXX: This could probably be replaced with a standard CMD COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] diff --git a/action.yml b/action.yml index 3333593..7bb4a33 100644 --- a/action.yml +++ b/action.yml @@ -40,7 +40,8 @@ inputs: required: false runs: using: 'docker' - image: 'docker://sentryintegrations/sentry-github-action-release:latest' + # If you change this, update the use-local-dockerfile action + image: 'docker://ghcr.io/getsentry/action-release-image:latest' branding: icon: 'triangle' color: 'purple'