From d53923ab037f0d56c9dc8821d1c27ecb5a4974b9 Mon Sep 17 00:00:00 2001 From: Ivan Vilanculo Date: Tue, 24 Jan 2023 16:32:43 +0200 Subject: [PATCH] feat: add container image (#431) * chore: include dist files into the github release * chore: fix build in ci script * chore: login to quay.io and docker-hub * chore: fix workflow issue * chore: push container images to remove registries * chore: list current directory * chore: checkout code before any action * fix: fix issue with the build image * chore: code cleanup * chore: update actions version * chore: format branch tag name to confront to docker image tag names * feat: add container image * fix: fix docker file path * chore: test push * chore: only push docker images on master and next branches * chore: code cleanup * chore: update docker hub descrption * chore: update bug template * docs: update badges * chore: only build docker image if the web service changes * only update docker read-me in master branches Co-authored-by: Ivan Vilanculo --- .github/ISSUE_TEMPLATE/bug_report.md | 20 ++--- .github/workflows/.docker.yml | 29 ------- .github/workflows/ci.yml | 17 ++-- .github/workflows/container-image.yml | 82 +++++++++++++++++++ .releaserc | 2 +- README.md | 2 +- packages/cli/src/index.ts | 1 + packages/service/Dockerfile | 67 +++++++++++++++ packages/service/README.md | 1 + packages/service/src/pdf-generator-service.ts | 1 + yarn.lock | 23 ++---- 11 files changed, 179 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/.docker.yml create mode 100644 .github/workflows/container-image.yml create mode 100644 packages/service/Dockerfile diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea78..b53ad740 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Create a report to help us improve title: '' -labels: '' +labels: 'bug' assignees: '' --- @@ -15,24 +15,18 @@ Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' -4. See error +4. See the error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** -If applicable, add screenshots to help explain your problem. +If applicable, could you add screenshots to help explain your problem? **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + - OS: [e.g. Ubuntu] + - Container runtime: [e.g. Docker] + - Version: [e.g. Docker version 20.10.22, build 3a2c30b] **Additional context** -Add any other context about the problem here. +Please feel free to add any other context about the problem here. diff --git a/.github/workflows/.docker.yml b/.github/workflows/.docker.yml deleted file mode 100644 index 467c40d1..00000000 --- a/.github/workflows/.docker.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Docker Image - -on: - push: - branches: [master] - pull_request: - branches: [master] - -jobs: - build-docker-image: - # if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: build - run: docker build --cache-from isneezy/pdf-generator -t isneezy/pdf-generator . - - name: lanunch docker container - run: docker run --rm -p 3000:3000 --name=service -d isneezy/pdf-generator -# - name: Test Generate Endpoint -# run: | -# curl -o test.pdf --location --request POST 'localhost:3000/generate' \ -# --header 'Content-Type: application/json' \ -# --data-raw '{ -# "content": "

Helo

" -# }' -# stat test.pdf - - name: cleanup - run: docker rm -f service && docker image rm isneezy/pdf-generator:latest - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35ebca0a..9cacda9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,22 +2,20 @@ name: CI on: push: - paths-ignore: - - "**/*.md" branches: [master, next] + paths-ignore: ["**/*.md"] pull_request: - paths-ignore: - - "**/*.md" branches: [master, next] + paths-ignore: ["**/*.md"] jobs: CI: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: 14.x - name: restore cache uses: actions/cache@v2 with: @@ -40,7 +38,10 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: build - run: yarn build + run: | + yarn build + cat packages/cli/dist/src/index.js + cat packages/service/dist/src/pdf-generator-service.js - name: cache build uses: actions/cache@v2 with: diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml new file mode 100644 index 00000000..3d39d4a4 --- /dev/null +++ b/.github/workflows/container-image.yml @@ -0,0 +1,82 @@ +name: container-images + +on: + push: + branches: [master, next] + paths: [packages/service, "!**/*.md"] + pull_request: + branches: [master, next] + paths: [packages/service, "!**/*.md"] + +jobs: + container-images: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 14.x + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to Quay.io + uses: docker/login-action@v2 + with: + registry: quay.io + username: ${{ secrets.QUAY_USERNAME }} + password: ${{ secrets.QUAY_ROBOT_TOKEN }} + + - name: Read container image tags + id: image-tags + run: | + echo "VERSION=$(cat packages/service/package.json | jq .version -r)" >> $GITHUB_OUTPUT + echo "BRANCH=$(echo "${{ github.head_ref || github.ref_name }}" | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z)" >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + file: packages/service/Dockerfile + tags: + isneezy/pdf-generator:${{ steps.image-tags.outputs.VERSION }}, + isneezy/pdf-generator:${{ steps.image-tags.outputs.BRANCH }}, + isneezy/pdf-generator:latest, + + isneezy/pdf-generator-service:${{ steps.image-tags.outputs.VERSION }}, + isneezy/pdf-generator-service:${{ steps.image-tags.outputs.BRANCH }}, + isneezy/pdf-generator-service:latest, + + quay.io/isneezy/pdf-generator-service:${{ steps.image-tags.outputs.VERSION }}, + quay.io/isneezy/pdf-generator-service:${{ steps.image-tags.outputs.BRANCH }}, + quay.io/isneezy/pdf-generator-service:latest, + push: ${{ (contains(github.ref, 'master') || contains(github.ref, 'next')) }} + + - name: Update legacy Docker Hub Description + if: ${{ (contains(github.ref, 'master') }} + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: isneezy/pdf-generator + short-description: 'A simple and yet powerful, versatile web service for converting HTML pages, templates, and URLs into high-quality PDF documents.' + readme-filepath: packages/service/README.md + + - name: Update Docker Hub Description + if: ${{ (contains(github.ref, 'master') }} + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: isneezy/pdf-generator-service + short-description: 'A simple and yet powerful, versatile web service for converting HTML pages, templates, and URLs into high-quality PDF documents.' + readme-filepath: packages/service/README.md \ No newline at end of file diff --git a/.releaserc b/.releaserc index 2f227ca0..b81e7c5b 100644 --- a/.releaserc +++ b/.releaserc @@ -7,7 +7,7 @@ [ "@semantic-release/git", { - "assets": ["package.json", "CHANGELOG.md"], + "assets": ["package.json", "CHANGELOG.md", "packages/*/dist"], "message": "chore(release): ${nextRelease.gitTag} [skip ci]\n\n${nextRelease.notes}" } ], diff --git a/README.md b/README.md index 0c0742f0..210b7754 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://img.shields.io/github/actions/workflow/status/isneezy/pdf-generator-service/ci.yml?branch=next&logo=github)](https://github.com/isneezy/pdf-generator-service/tree/next) [![Coverage Status](https://coveralls.io/repos/github/isneezy/pdf-generator-service/badge.svg?branch=next)](https://coveralls.io/github/isneezy/pdf-generator-service?branch=next) -[![Docker Repository on Quay](https://quay.io/repository/isneezy/pdf-generator-service/status "Docker Repository on Quay")](https://quay.io/repository/isneezy/pdf-generator-service) +![Build status](https://img.shields.io/github/actions/workflow/status/isneezy/pdf-generator-service/container-image.yml?branch=next&label=image%20build&logo=docker) A powerful and versatile tool for converting HTML pages, templates, and URLs into high-quality PDF documents using Chromium and Puppeteer. diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 137cb992..b58f1f8a 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node + import { resolve } from 'path' import { writeFileSync, existsSync, readFileSync } from 'fs' import pkg from '../package.json' diff --git a/packages/service/Dockerfile b/packages/service/Dockerfile new file mode 100644 index 00000000..6d6ac530 --- /dev/null +++ b/packages/service/Dockerfile @@ -0,0 +1,67 @@ +FROM node:lts-alpine3.12 AS base + +# Installs latest Chromium package. +RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/main" > /etc/apk/repositories \ + && echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \ + && echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \ + && echo "http://dl-cdn.alpinelinux.org/alpine/v3.11/main" >> /etc/apk/repositories \ + && apk upgrade -U -a \ + && apk add --no-cache \ + libstdc++ \ + chromium \ + harfbuzz \ + nss \ + freetype \ + ttf-freefont \ + && rm -rf /var/cache/* \ + && mkdir /var/cache/apk + +# Add Chrome as a user +RUN mkdir -p /app \ + && adduser -D chrome \ + && chown -R chrome:chrome /app + +# Run Chrome as non-privileged +USER chrome +WORKDIR /app + +ENV CHROME_BIN=/usr/bin/chromium-browser \ + CHROME_PATH=/usr/lib/chromium/ \ + PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ + PUPPETEER_ARGS='--no-sandbox --disable-setuid-sandbox' \ + PUPPETEER_PREVENT_INTERNAL_CHROMIUM='yes' \ + PUPPETEER_SKIP_DOWNLOAD='yes' + +FROM base AS builder + +COPY --chown=chrome:chrome package.json . +COPY --chown=chrome:chrome packages/service/package.json ./packages/service/package.json +COPY --chown=chrome:chrome packages/library/package.json ./packages/library/package.json + +COPY --chown=chrome:chrome yarn.lock . +COPY --chown=chrome:chrome packages/service/package.json ./packages/service/yarn.lock +COPY --chown=chrome:chrome packages/library/package.json ./packages/library/yarn.lock + +RUN yarn install --check-files --frozen-lockfile --non-interactive && yarn cache dir + +COPY --chown=chrome:chrome . . + +# Test and build +RUN CI=true yarn test && yarn build + +FROM base +COPY --chown=chrome:chrome package.json . +COPY --chown=chrome:chrome packages/service/package.json ./packages/service/package.json +COPY --chown=chrome:chrome packages/library/package.json ./packages/library/package.json + +COPY --chown=chrome:chrome yarn.lock . +COPY --chown=chrome:chrome packages/service/package.json ./packages/service/yarn.lock +COPY --chown=chrome:chrome packages/library/package.json ./packages/library/yarn.lock + +RUN yarn install --production && yarn cache clean && chown -R chrome:chrome ./ + +COPY --from=builder --chown=chrome:chrome /app/packages/library/dist ./packages/library/dist +COPY --from=builder --chown=chrome:chrome /app/packages/service/dist ./packages/service/dist + +EXPOSE 3000 +CMD ["node", "packages/service/dist/src/pdf-generator-service.js"] \ No newline at end of file diff --git a/packages/service/README.md b/packages/service/README.md index 7e25d1f9..f8736871 100644 --- a/packages/service/README.md +++ b/packages/service/README.md @@ -2,6 +2,7 @@ [![Build Status](https://img.shields.io/github/actions/workflow/status/isneezy/pdf-generator-service/ci.yml?branch=next&logo=github)](https://github.com/isneezy/pdf-generator-service/tree/next) [![Coverage Status](https://coveralls.io/repos/github/isneezy/pdf-generator-service/badge.svg?branch=next)](https://coveralls.io/github/isneezy/pdf-generator-service?branch=next) +![Build status](https://img.shields.io/github/actions/workflow/status/isneezy/pdf-generator-service/container-image.yml?branch=next&label=docker%20build&logo=docker) ![npm (tag)](https://img.shields.io/npm/v/@isneezy/pdf-generator/next?logo=npm) `@isneezy/pdf-generator-service` is a web service that allows you to easily generate PDFs from a web interface. diff --git a/packages/service/src/pdf-generator-service.ts b/packages/service/src/pdf-generator-service.ts index 9f564dba..9aba5786 100644 --- a/packages/service/src/pdf-generator-service.ts +++ b/packages/service/src/pdf-generator-service.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node + import { program } from 'commander' import pkg from '../package.json' import { createApp } from './app' diff --git a/yarn.lock b/yarn.lock index 294c1d5d..fef89a2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1589,18 +1589,18 @@ "@types/node" "*" "@types/express-serve-static-core@^4.17.31": - version "4.17.32" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz#93dda387f5516af616d8d3f05f2c4c79d81e1b82" - integrity sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA== + version "4.17.33" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" + integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" "@types/express@^4.17.15": - version "4.17.15" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.15.tgz#9290e983ec8b054b65a5abccb610411953d417ff" - integrity sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ== + version "4.17.16" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.16.tgz#986caf0b4b850611254505355daa24e1b8323de8" + integrity sha512-LkKpqRZ7zqXJuvoELakaFYuETHjZkSol8EV6cNnyishutDBCCdv6+dsKPbKkCcIk57qRphOLY5sEgClw1bO3gA== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "^4.17.31" @@ -5709,8 +5709,8 @@ normalize-package-data@^4.0.0: normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz" - integrity "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^6.0.0: version "6.1.0" @@ -6426,12 +6426,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4: - version "2.2.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" - integrity "sha1-RlVH81nMwgbTxI5Goby4m/fuYZ0= sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" - -picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==