From 4d43346a6bbfbbb45150d2750ebad233284920ba Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 6 Oct 2024 02:28:04 +0900 Subject: [PATCH 1/5] Renew docker image to change the base from Alpine Linux to Debian --- .dockerignore | 6 +++- Dockerfile | 70 +++++++++++++++++++++++++---------------------- docker-entrypoint | 4 +-- 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/.dockerignore b/.dockerignore index dd4d6451..619b4f21 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,11 @@ **/* -!lib/ +!src/ +!scripts/ !docker-entrypoint !LICENSE !marp-cli.js !package.json !package-lock.json +!postcss.config.js +!rollup.config.mjs +!tsconfig.json diff --git a/Dockerfile b/Dockerfile index 8a2e0a12..17dbcaca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,40 +1,46 @@ -FROM node:20.17.0-alpine -LABEL maintainer "Marp team" - -RUN apk update && apk upgrade && \ - echo @edge http://dl-cdn.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \ - echo @edge http://dl-cdn.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \ - echo @edge http://dl-cdn.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && \ - apk add --no-cache \ - grep \ - chromium@edge \ - freetype@edge \ - libstdc++@edge \ - ttf-liberation@edge \ - font-noto-cjk@edge \ - font-noto-devanagari@edge \ - font-noto-arabic@edge \ - font-noto-bengali@edge \ - nss@edge \ - wayland-dev@edge \ - su-exec - -RUN addgroup -S marp && adduser -S -g marp marp \ - && mkdir -p /home/marp/app /home/marp/.cli \ - && chown -R marp:marp /home/marp +#################### Build Marp CLI #################### +FROM node:20.17.0-bookworm-slim AS build +WORKDIR /home/node/marp-cli +COPY . . +RUN npm ci && npm run build -USER marp -ENV CHROME_PATH /usr/bin/chromium-browser +#################### Create Marp CLI image #################### +FROM node:20.17.0-bookworm-slim + +# Set up user for Marp CLI +RUN groupadd -r marp && useradd -r -g marp marp && mkdir -p /home/marp/app /home/marp/.cli && chown -R marp:marp /home/marp + +# Install Chromium +# (Use Chromium from "Playwright" instead of Puppeteer, for getting ARM64 build, which is not provided by Puppeteer) +RUN mkdir -p /tmp/marp-cli-chromium && \ + cd /tmp/marp-cli-chromium && \ + npm i playwright@latest && \ + PLAYWRIGHT_BROWSERS_PATH=/usr/local/bin/pw-browsers npx playwright install --with-deps chromium && \ + ln -s $(find /usr/local/bin/pw-browsers -name "chrome" -executable | head -n 1) /usr/local/bin/chrome && \ + rm -rf /tmp/marp-cli-chromium + +# Install dependencies +RUN apt update && \ + apt install -y --no-install-recommends gosu && \ + apt clean && \ + rm -rf /var/lib/apt/lists/* && \ + npm cache clean --force +# Set environments +ENV MARP_USER=marp:marp PATH=$PATH:/home/marp/.cli CHROME_PATH=/usr/local/bin/chrome + +# Copy Marp CLI files +USER marp WORKDIR /home/marp/.cli -COPY --chown=marp:marp . . -RUN npm ci && npm cache clean --force && node marp-cli.js --version +COPY --chown=marp:marp package.json package-lock.json marp-cli.js LICENSE docker-entrypoint ./ +RUN npm ci --omit=dev && npm cache clean --force -# Setup workspace for user -USER root -ENV MARP_USER marp:marp -ENV PATH $PATH:/home/marp/.cli +# Copy built files +COPY --chown=marp:marp --from=build /home/node/marp-cli/lib/ ./lib/ +# Set up image +USER root WORKDIR /home/marp/app ENTRYPOINT ["docker-entrypoint"] CMD ["--help"] +LABEL maintainer="Marp team" diff --git a/docker-entrypoint b/docker-entrypoint index ee39f74d..f6be21d8 100755 --- a/docker-entrypoint +++ b/docker-entrypoint @@ -1,3 +1,3 @@ -#!/bin/ash +#!/bin/sh -exec su-exec "$MARP_USER" node /home/marp/.cli/marp-cli.js "$@" +exec gosu "$MARP_USER" node /home/marp/.cli/marp-cli.js "$@" From 2dcad7c5b34483239dbd76351dc71747c78f57bc Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 6 Oct 2024 02:29:48 +0900 Subject: [PATCH 2/5] Disable Docker build on CI workflow --- .circleci/config.yml | 193 ++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 112 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 212425ad..687a5bb9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,13 +17,13 @@ executors: - image: cimg/node:<< parameters.version >><<# parameters.browser >>-browsers<> working_directory: ~/marp-cli - docker: - machine: - image: ubuntu-2204:2023.04.2 - docker_layer_caching: true - working_directory: ~/marp-cli - environment: - DOCKER_BUILDKIT: 1 + # docker: + # machine: + # image: ubuntu-2204:2023.04.2 + # docker_layer_caching: true + # working_directory: ~/marp-cli + # environment: + # DOCKER_BUILDKIT: 1 commands: install: @@ -120,57 +120,57 @@ commands: paths: - lib - docker: - parameters: - tag: - type: string - default: latest - user: - type: env_var_name - default: DOCKER_USER - pass: - type: env_var_name - default: DOCKER_PASS - machine: - type: boolean - default: false - steps: - - checkout - - - attach_workspace: - at: ~/marp-cli - - - unless: - condition: << parameters.machine >> - steps: - - setup_remote_docker: - version: '20.10.2' - - - run: - name: Login to Docker Hub - command: docker login -u ${<< parameters.user >>} -p ${<< parameters.pass >>} - - - run: - name: Install Docker buildx - command: | - docker build --platform=local --quiet -o ~ "https://github.com/docker/buildx.git#v0.8.1" - mkdir -p ~/.docker/cli-plugins - mv ~/buildx ~/.docker/cli-plugins/docker-buildx - environment: - DOCKER_BUILDKIT: 1 - - - run: - name: Setup QEMU - command: docker run --privileged --rm tonistiigi/binfmt --install all - - - run: - name: Build Docker image and push to Docker Hub - command: | - docker context create builder - docker buildx create --use builder - docker buildx build --no-cache --platform linux/amd64,linux/arm64 --progress plain --push -t marpteam/marp-cli:<< parameters.tag >> . - environment: - DOCKER_CLI_EXPERIMENTAL: enabled + # docker: + # parameters: + # tag: + # type: string + # default: latest + # user: + # type: env_var_name + # default: DOCKER_USER + # pass: + # type: env_var_name + # default: DOCKER_PASS + # machine: + # type: boolean + # default: false + # steps: + # - checkout + + # - attach_workspace: + # at: ~/marp-cli + + # - unless: + # condition: << parameters.machine >> + # steps: + # - setup_remote_docker: + # version: '20.10.2' + + # - run: + # name: Login to Docker Hub + # command: docker login -u ${<< parameters.user >>} -p ${<< parameters.pass >>} + + # - run: + # name: Install Docker buildx + # command: | + # docker build --platform=local --quiet -o ~ "https://github.com/docker/buildx.git#v0.8.1" + # mkdir -p ~/.docker/cli-plugins + # mv ~/buildx ~/.docker/cli-plugins/docker-buildx + # environment: + # DOCKER_BUILDKIT: 1 + + # - run: + # name: Setup QEMU + # command: docker run --privileged --rm tonistiigi/binfmt --install all + + # - run: + # name: Build Docker image and push to Docker Hub + # command: | + # docker context create builder + # docker buildx create --use builder + # docker buildx build --no-cache --platform linux/amd64,linux/arm64 --progress plain --push -t marpteam/marp-cli:<< parameters.tag >> . + # environment: + # DOCKER_CLI_EXPERIMENTAL: enabled jobs: audit: @@ -211,29 +211,29 @@ jobs: - test # Docker - docker-build-latest: - executor: node - steps: - - build - - docker-image-latest: - executor: docker - steps: - - docker: - tag: latest - machine: true - - docker-build-tag: - executor: node - steps: - - build - - docker-image-tag: - executor: docker - steps: - - docker: - tag: $CIRCLE_TAG - machine: true + # docker-build-latest: + # executor: node + # steps: + # - build + + # docker-image-latest: + # executor: docker + # steps: + # - docker: + # tag: latest + # machine: true + + # docker-build-tag: + # executor: node + # steps: + # - build + + # docker-image-tag: + # executor: docker + # steps: + # - docker: + # tag: $CIRCLE_TAG + # machine: true workflows: test: @@ -249,34 +249,3 @@ workflows: - test-node22: requires: - audit - - # Docker (latest) - - docker-build-latest: - requires: - - test-node18 - - test-node20 - - test-node22 - filters: - branches: - only: main - - - docker-image-latest: - requires: - - docker-build-latest - - # Docker (tag) - - docker-build-tag: - filters: - branches: - ignore: /.*/ - tags: - only: /^v.*/ - - - docker-image-tag: - requires: - - docker-build-tag - filters: - branches: - ignore: /.*/ - tags: - only: /^v.*/ From ee1caae729c15ded9befac0e5bfc60657d129eff Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 6 Oct 2024 05:18:48 +0900 Subject: [PATCH 3/5] Add new GitHub Actions workflow to build multi-arch images and push into multi registries --- .circleci/config.yml | 86 ------------------- .github/workflows/build-image.yml | 134 ++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 86 deletions(-) create mode 100644 .github/workflows/build-image.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 687a5bb9..cc017eab 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,14 +17,6 @@ executors: - image: cimg/node:<< parameters.version >><<# parameters.browser >>-browsers<> working_directory: ~/marp-cli - # docker: - # machine: - # image: ubuntu-2204:2023.04.2 - # docker_layer_caching: true - # working_directory: ~/marp-cli - # environment: - # DOCKER_BUILDKIT: 1 - commands: install: parameters: @@ -120,58 +112,6 @@ commands: paths: - lib - # docker: - # parameters: - # tag: - # type: string - # default: latest - # user: - # type: env_var_name - # default: DOCKER_USER - # pass: - # type: env_var_name - # default: DOCKER_PASS - # machine: - # type: boolean - # default: false - # steps: - # - checkout - - # - attach_workspace: - # at: ~/marp-cli - - # - unless: - # condition: << parameters.machine >> - # steps: - # - setup_remote_docker: - # version: '20.10.2' - - # - run: - # name: Login to Docker Hub - # command: docker login -u ${<< parameters.user >>} -p ${<< parameters.pass >>} - - # - run: - # name: Install Docker buildx - # command: | - # docker build --platform=local --quiet -o ~ "https://github.com/docker/buildx.git#v0.8.1" - # mkdir -p ~/.docker/cli-plugins - # mv ~/buildx ~/.docker/cli-plugins/docker-buildx - # environment: - # DOCKER_BUILDKIT: 1 - - # - run: - # name: Setup QEMU - # command: docker run --privileged --rm tonistiigi/binfmt --install all - - # - run: - # name: Build Docker image and push to Docker Hub - # command: | - # docker context create builder - # docker buildx create --use builder - # docker buildx build --no-cache --platform linux/amd64,linux/arm64 --progress plain --push -t marpteam/marp-cli:<< parameters.tag >> . - # environment: - # DOCKER_CLI_EXPERIMENTAL: enabled - jobs: audit: executor: node @@ -210,35 +150,9 @@ jobs: - lint - test - # Docker - # docker-build-latest: - # executor: node - # steps: - # - build - - # docker-image-latest: - # executor: docker - # steps: - # - docker: - # tag: latest - # machine: true - - # docker-build-tag: - # executor: node - # steps: - # - build - - # docker-image-tag: - # executor: docker - # steps: - # - docker: - # tag: $CIRCLE_TAG - # machine: true - workflows: test: jobs: - # Test - audit - test-node18: requires: diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml new file mode 100644 index 00000000..95baaafd --- /dev/null +++ b/.github/workflows/build-image.yml @@ -0,0 +1,134 @@ +name: Build image + +on: + push: + branches: + - main + tags: + - v* + +env: + GITHUB_CONTAINER_REGISTRY_IMAGE: ghcr.io/marp-team/marp-cli + DOCKER_HUB_REGISTRY_IMAGE: marpteam/marp-cli + +jobs: + build: + runs-on: ${{ matrix.runner }} + + strategy: + fail-fast: false + matrix: + include: + - runner: ubuntu-latest + platform: linux/amd64 + + # TODO: Change to ARM64 runner for open-sourced project if available (M1 Mac cannot run Docker due to lack of nested virtualization) + - runner: ubuntu-latest + platform: linux/arm64 + + steps: + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }} + ${{ env.DOCKER_HUB_REGISTRY_IMAGE }} + + # TODO: It is removable if ARM64 runner is available + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: 'type=registry,"name=${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }},${{ env.DOCKER_HUB_REGISTRY_IMAGE }}",push-by-digest=true,name-canonical=true' + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }} + ${{ env.DOCKER_HUB_REGISTRY_IMAGE }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }}")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }}@sha256:%s ' *) + docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("${{ env.DOCKER_HUB_REGISTRY_IMAGE }}")) | "-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKER_HUB_REGISTRY_IMAGE }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.GITHUB_CONTAINER_REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.DOCKER_HUB_REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} From b48da6c43dda1df7e982f426b2b8847acbbefa6d Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 6 Oct 2024 05:35:28 +0900 Subject: [PATCH 4/5] Update Dockerfile to build Marp CLI by using current platform --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 17dbcaca..c34a63f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #################### Build Marp CLI #################### -FROM node:20.17.0-bookworm-slim AS build +FROM --platform=$BUILDPLATFORM node:20.17.0-bookworm-slim AS build WORKDIR /home/node/marp-cli COPY . . RUN npm ci && npm run build From 3f22707589ee8bcba80a06300d2b70a6608d8bc9 Mon Sep 17 00:00:00 2001 From: Yuki Hattori Date: Sun, 6 Oct 2024 06:19:40 +0900 Subject: [PATCH 5/5] [ci skip] Update CHANGELOG.md and README.md --- CHANGELOG.md | 12 +++++++++--- README.md | 26 +++++++++++++++++++------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7a9ae3f..98534549 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,17 @@ ## [Unreleased] -### Breaking +> [!IMPORTANT] +> +> See also https://github.com/orgs/marp-team/discussions/533 about new changes in Marp Core. + +### ⚡️ Breaking - End-of-Lifed Node.js 16 is no longer supported, and required Node.js 18 and later ([#591](https://github.com/marp-team/marp-cli/pull/591)) - Upgrade Marp Core to [v4.0.0](https://github.com/marp-team/marp-core/releases/v4.0.0) ([#591](https://github.com/marp-team/marp-cli/pull/591)) - The slide container of built-in themes became the block element and adopted safe centering - Relax HTML allowlist: Allowed a lot of HTML elements and attributes by default +- The container image is now based on Debian instead of Alpine ([#608](https://github.com/marp-team/marp-cli/pull/608)) ### Added @@ -15,14 +20,15 @@ - `--browser` and some related options to control the browser for conversion ([#603](https://github.com/marp-team/marp-cli/pull/603)) - Find Chrome and Edge from the host Windows as a fallback when [WSL 2 networking is mirrored mode](https://learn.microsoft.com/windows/wsl/networking#mirrored-mode-networking) ([#604](https://github.com/marp-team/marp-cli/pull/604)) - `--debug` (`-d`) option to CLI interface ([#599](https://github.com/marp-team/marp-cli/pull/599)) +- Publish the container image to GitHub Container Registry ([#578](https://github.com/marp-team/marp-cli/issues/578), [#608](https://github.com/marp-team/marp-cli/pull/608)) - CI testing against Node.js v22 ([#591](https://github.com/marp-team/marp-cli/pull/591)) ### Changed -- Use [the new headless mode of Chrome](https://developer.chrome.com/docs/chromium/headless) while converting by default ([#593](https://github.com/marp-team/marp-cli/pull/593)) - - You can get back to the old headless mode by setting `PUPPETEER_HEADLESS_MODE=old` env. - Upgrade Marpit to [v3.1.1](https://github.com/marp-team/marpit/releases/tag/v3.1.1) ([#591](https://github.com/marp-team/marp-cli/pull/591)) - Support for CSS nesting +- Use [the new headless mode of Chrome](https://developer.chrome.com/docs/chromium/headless) while converting by default ([#593](https://github.com/marp-team/marp-cli/pull/593)) + - You can get back to the old headless mode by setting `PUPPETEER_HEADLESS_MODE=old` env. - Upgrade development Node.js LTS to v20.17.0 ([#591](https://github.com/marp-team/marp-cli/pull/591)) - Upgrade dependent packages to the latest versions ([#591](https://github.com/marp-team/marp-cli/pull/591), [#598](https://github.com/marp-team/marp-cli/pull/598)) - Migrate ESLint config to flat config ([#606](https://github.com/marp-team/marp-cli/pull/606)) diff --git a/README.md b/README.md index 4f721d27..4df7a842 100644 --- a/README.md +++ b/README.md @@ -50,14 +50,26 @@ npx @marp-team/marp-cli@latest -s ./slides [microsoft edge]: https://www.microsoft.com/edge [mozilla firefox]: https://www.mozilla.org/firefox/new/ -### Docker +### Container image -Don't you like installing Node.js and Chrome to local? We have [an official Docker image `marpteam/marp-cli`][marp-cli-docker] ready to use CLI. +Don't you like installing Node.js and Chrome to local? We have an official container image that is ready to use CLI. -[Please refer how to use at Docker Hub.][marp-cli-docker] +[**⏩ Please refer how to use at Docker Hub.**][marp-cli-docker] [marp-cli-docker]: https://hub.docker.com/r/marpteam/marp-cli/ +#### [Docker Hub][marp-cli-docker] + +```bash +docker pull marpteam/marp-cli +``` + +#### [GitHub Container Registry](https://github.com/marp-team/marp-cli/pkgs/container/marp-cli) + +```bash +docker pull ghcr.io/marp-team/marp-cli +``` + ## Install ### Use package manager @@ -109,7 +121,7 @@ npm install -g @marp-team/marp-cli We also provide standalone binaries for Linux, macOS, and Windows. These have bundled Marp CLI with Node.js binary, so no need to install Node.js separately. -**[:fast_forward: Download the latest standalone binary from release page.][releases]** +**[⏩ Download the latest standalone binary from release page.][releases]** [releases]: https://github.com/marp-team/marp-cli/releases @@ -548,7 +560,7 @@ By using `--version` (`-v`) option, you may confirm the version of engine that i ```console $ marp --version -@marp-team/marp-cli v1.x.x (w/ @marp-team/marp-core v2.x.x) +@marp-team/marp-cli v41.x.x (w/ @marp-team/marp-core v4.x.x) ``` ### Use specific version of Marp Core @@ -558,9 +570,9 @@ Marp CLI prefers to use _an installed core to local project by user_ than the bu If the current project has installed `@marp-team/marp-core` individually, it would show its version and the annotation: `w/ user-installed @marp-team/marp-core vX.X.X` or `w/ customized engine`. ```console -$ npm i @marp-team/marp-cli @marp-team/marp-core@^3.2.0 --save-dev +$ npm i @marp-team/marp-cli @marp-team/marp-core@^4.0.0 --save-dev $ npx marp --version -@marp-team/marp-cli v2.x.x (w/ user-installed @marp-team/marp-core v3.2.0) +@marp-team/marp-cli v4.x.x (w/ user-installed @marp-team/marp-core v4.0.0) ``` ## Configuration file