Introduce farm plugins ci
Recently, I have been working on a project that requires me to support both JavaScript and Rust plugins. I have been using GitHub Actions to deploy the plugins, and I wanted to share how I managed to support both JavaScript and Rust plugins in the same repository.
Rust Plugins#
Building Rust Plugins#
Bacause of rust plugin need support multi-platform, so we should build in multi-platform before deploy to npm registry.
yaml
name: Building Rust Binding And Upload Artifactson: workflow_calljobs:build:name: Build and Upload Artifacts - ${{ matrix.settings.abi }}runs-on: ${{ matrix.settings.os }}strategy:fail-fast: falsematrix:settings:- os: ubuntu-latestdocker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debianabi: linux-x64-gnubuild: >-git config --global --add safe.directory /build &&set -e &&unset CC_x86_64_unknown_linux_gnu &&unset CC &&pnpm --filter "{rust-plugins}[HEAD~1]" --sequential build --target x86_64-unknown-linux-gnu --abi linux-x64-gnu- os: ubuntu-latestdocker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpineabi: linux-x64-muslbuild: >-git config --global --add safe.directory /build &&set -e &&unset CC_x86_64_unknown_linux_musl &&unset CC &&pnpm --filter "{rust-plugins}[HEAD~1]" --sequential build --target x86_64-unknown-linux-musl --abi linux-x64-musl- os: windows-latestabi: win32-x64-msvc- os: macos-latestabi: darwin-arm64- os: macos-13abi: darwin-x64# cross compile# windows. Note swc plugins is not supported on ia32 and arm64- os: windows-latestabi: win32-ia32-msvctarget: i686-pc-windows-msvcbuild: |export CARGO_PROFILE_RELEASE_LTO=falsecargo install cargo-xwin --lockedpnpm --filter "{rust-plugins}[HEAD~1]" --sequential build --target i686-pc-windows-msvc --abi win32-ia32-msvc --cargo-flags="--no-default-features"- os: windows-latestabi: win32-arm64-msvctarget: aarch64-pc-windows-msvcbuild: |export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=256export CARGO_PROFILE_RELEASE_LTO=falsecargo install cargo-xwin --lockedpnpm --filter "{rust-plugins}[HEAD~1]" --sequential build --target aarch64-pc-windows-msvc --abi win32-arm64-msvc --cargo-flags="--no-default-features"# linux- os: ubuntu-latestabi: linux-arm64-musltarget: aarch64-unknown-linux-muslzig: true- os: ubuntu-latestabi: linux-arm64-gnutarget: aarch64-unknown-linux-gnuzig: truesteps:- uses: actions/checkout@v3with:fetch-depth: 2# - run: |# git fetch --no-tags --prune --depth=1 origin +refs/heads/main:refs/remotes/HEAD~1- name: Cache rust artifactsuses: Swatinem/rust-cache@v2with:shared-key: rust-build-${{ matrix.settings.abi }}- uses: actions/setup-node@v3with:node-version: 18- name: Install Dependenciesrun: npm config set registry https://registry.npmmirror.com && npm install -g [email protected] && pnpm i --frozen-lockfile- run: rustup target add ${{ matrix.settings.target }}if: ${{ matrix.settings.target }}# Use the v1 of this action- uses: mbround18/setup-osxcross@v1if: ${{ matrix.settings.osxcross }}# This builds executables & sets env variables for rust to consume.with:osx-version: '12.3'- uses: goto-bus-stop/setup-zig@v2if: ${{ matrix.settings.zig }}- name: Build in dockeruses: addnab/docker-run-action@v3if: ${{ matrix.settings.docker }}with:image: ${{ matrix.settings.docker }}options: -v ${{ env.HOME }}/.cargo/git:/root/.cargo/git -v ${{ env.HOME }}/.cargo/registry:/root/.cargo/registry -v ${{ github.workspace }}:/build -w /buildrun: ${{ matrix.settings.build }}- name: Default Buildif: ${{ !matrix.settings.docker && !matrix.settings.build }}run: |pnpm --filter "{rust-plugins}[HEAD~1]" --sequential build --abi ${{ matrix.settings.abi }} ${{ matrix.settings.target && format('--target {0}', matrix.settings.target) || '' }} ${{ matrix.settings.zig && '--zig' || '' }}shell: bash- name: Buildif: ${{ !matrix.settings.docker && matrix.settings.build }}run: ${{ matrix.settings.build }}shell: bash- name: Upload Plugin dsvuses: actions/upload-artifact@v3with:name: ${{ github.sha }}-${{ matrix.settings.abi }}-dsvpath: ./rust-plugins/dsv/npm/${{ matrix.settings.abi }}/index.farmif-no-files-found: ignore# other packages upload
In the above ci config, first we build defferent platform rust plugins. But in then build step, we use pnpm --filter "{rust-plugins}[HEAD~1]"
to build only changed rust plugins. This is very important, because we don't want to build all rust plugins every time. Then filter only build changed rust plugins under rust-plugins
directory.
Deploying Rust Plugins#
yaml
name: Publish packages and crateson:push:branches:- mainconcurrency: ${{ github.workflow }}-${{ github.ref }}jobs:call-rust-build:if: contains(github.event.head_commit.message, 'rust-plugins') || contains(github.event.head_commit.message, 'all')uses: ./.github/workflows/build.yamlrelease:name: Releaseif: contains(github.event.head_commit.message, 'rust-plugins') || contains(github.event.head_commit.message, 'all')needs: [call-rust-build]runs-on: ubuntu-lateststeps:- name: Checkout Repouses: actions/checkout@v3with:fetch-depth: 2- run: |git fetch --no-tags --prune --depth=1 origin +refs/heads/main:refs/remotes/HEAD~1- name: Setup Node.js 18.xuses: actions/setup-node@v3with:node-version: 18.x# batch download artifacts- uses: actions/download-artifact@v3with:path: /tmp/artifacts- name: Move Artifactsrun: |for abi in linux-x64-gnu linux-x64-musl darwin-x64 win32-x64-msvc linux-arm64-musl linux-arm64-gnu darwin-arm64 win32-ia32-msvc win32-arm64-msvcdofor package in dsv react-components virtual yaml strip image url icons auto-import mdxdofolder_path="/tmp/artifacts/${{github.sha}}-${abi}-${package}"if [ -d "${folder_path}" ] && [ -n "$(ls -A $folder_path)" ]; thenmv /tmp/artifacts/${{ github.sha }}-${abi}-${package}/* ./packages/${package}/npm/${abi}ls -R $folder_pathls -R ./packages/${package}/npm/${abi}test -f ./packages/${package}/npm/${abi}/index.farmelseecho "${folder_path} is empty"fidonedone- name: Install Dependencies- name: Publish to npmrun: |npm set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} && npm config set access public && pnpm --filter "{rust-plugins}[HEAD~1]" publish --no-git-checks
In the above ci config, we use contains
to determine whether to run the ci. If the commit message contains rust-plugins
or all
, then we run the ci. In the release
job, we first download the artifacts that we built in the previous ci. Then we move the artifacts to the corresponding directory. Finally, we publish the rust plugins to the npm registry.
JavaScript Plugins#
Building JavaScript Plugins#
yaml
name: PR build pluginson: workflow_calljobs:build:runs-on: ubuntu-latestname: releasesteps:- uses: actions/checkout@v3with:fetch-depth: 2# - run: |# git fetch --no-tags --prune --depth=1 origin +refs/heads/main:refs/remotes/HEAD~1- name: Setup Nodeuses: actions/setup-node@v3with:node-version: 20registry-url: https://registry.npmjs.org/- name: Enable Corepackid: pnpm-setuprun: |corepack enable- name: Initliaze .npmrcrun: >echo -e "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}\n$(cat .npmrc)" > .npmrc&& cat -n .npmrc- name: pnpm installrun: pnpm install --frozen-lockfile- name: Build Packagesrun: |pnpm --filter "{js-plugins}[HEAD~1]" build
the config is as same as rust plugins, but we use pnpm --filter "{js-plugins}[HEAD~1]" build
to build only changed js plugins.
Deploying JavaScript Plugins#
yaml
name: Release Packageson:push:branches:- mainjobs:release:runs-on: ubuntu-latestif: contains(github.event.head_commit.message, 'js-plugins') || contains(github.event.head_commit.message, 'all')name: releasesteps:- name: Checkout repouses: actions/checkout@v3with:fetch-depth: 2- name: Setup Nodeuses: actions/setup-node@v3with:node-version: 20registry-url: https://registry.npmjs.org/- name: Enable Corepackid: pnpm-setuprun: |corepack enable- name: Initliaze .npmrcrun: >echo -e "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}\n$(cat .npmrc)" > .npmrc&& cat -n .npmrc- name: pnpm installrun: pnpm install --frozen-lockfile- name: Build Packagesrun: |pnpm --filter "{js-plugins}[HEAD~1]" build- name: Release and Publish Packagesrun: |npm set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} && npm config set access public && pnpm --filter "{js-plugins}[HEAD~1]" publish --no-git-checks
the relase config is as same as rust plugins too.
Summary#
- use
pnpm --filter "{xx}[HEAD~1]"
to build only changed to reduce build time. - use
contains
to determine whether to run the ci.