diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5db5cd38d..e9ba2b4fa 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,5 +1,12 @@ name: Test -on: [push, pull_request] +on: + push: + paths-ignore: + - ".github/workflows/prebuild.yaml" + pull_request: + paths-ignore: + - ".github/workflows/prebuild.yaml" + jobs: Linux: diff --git a/.github/workflows/prebuild.yaml b/.github/workflows/prebuild.yaml new file mode 100644 index 000000000..b75e7fed0 --- /dev/null +++ b/.github/workflows/prebuild.yaml @@ -0,0 +1,238 @@ +# Triggering prebuilds: +# 1. Create a draft release manually using the GitHub UI. +# 2. Set the `jobs.*.strategy.matrix.node` arrays to the set of Node.js versions +# to build for. +# 3. Set the `jobs.*.strategy.matrix.canvas_tag` arrays to the set of Canvas +# tags to build. (Usually this is a single tag, but can be an array when a +# new version of Node.js is released and older versions of Canvas need to be +# built.) +# 4. Commit and push this file to master. +# 5. Once the builds succeed, promote the draft release to a full release. + +name: Make Prebuilds +on: + push: + branches: + - 'master' + paths: + - '.github/workflows/prebuild.yaml' +# UPLOAD_TO can be specified to upload the release assets under a different tag +# name (e.g. for testing). If omitted, the assets are published under the same +# release tag as the canvas version being built. +# env: +# UPLOAD_TO: "v0.0.1" + +jobs: + Linux: + strategy: + matrix: + node: [8, 9, 10, 11, 12, 13, 14] + canvas_tag: [] # e.g. "v2.6.1" + name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, Linux + runs-on: ubuntu-latest + container: + image: chearon/canvas-prebuilt:7 + env: + CANVAS_VERSION_TO_BUILD: ${{ matrix.canvas_tag }} + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ matrix.canvas_tag }} + + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - name: Build + run: | + npm install -g node-gyp + npm install --ignore-scripts + . prebuild/Linux/preinstall.sh + cp prebuild/Linux/binding.gyp binding.gyp + node-gyp rebuild -j 2 + . prebuild/Linux/bundle.sh + + - name: Test binary + run: | + cd /root/harfbuzz-* && make uninstall + cd /root/cairo-* && make uninstall + cd /root/pango-* && make uninstall + cd /root/libpng-* && make uninstall + cd /root/libjpeg-* && make uninstall + cd /root/giflib-* && make uninstall + cd $GITHUB_WORKSPACE && npm test + + - name: Make bundle + id: make_bundle + run: . prebuild/tarball.sh + + - name: Upload + uses: actions/github-script@0.9.0 + with: + script: | + const fs = require("fs"); + const assetName = "${{ steps.make_bundle.outputs.asset_name }}"; + const tagName = process.env.UPLOAD_TO || process.env.CANVAS_VERSION_TO_BUILD; + const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); + + const releases = await github.repos.listReleases({owner, repo}); + const release = releases.data.find(r => r.tag_name === tagName); + if (!release) + throw new Error(`Tag ${tagName} not found. Did you make the GitHub release?`); + + const oldAsset = release.assets.find(a => a.name === assetName); + if (oldAsset) + await github.repos.deleteReleaseAsset({owner, repo, asset_id: oldAsset.id}); + + // (This is equivalent to actions/upload-release-asset. We're + // already in a script, so might as well do it here.) + const r = await github.repos.uploadReleaseAsset({ + url: release.upload_url, + headers: { + "content-type": "application/x-gzip", + "content-length": `${fs.statSync(assetName).size}` + }, + name: assetName, + data: fs.readFileSync(assetName) + }); + + macOS: + strategy: + matrix: + node: [8, 9, 10, 11, 12, 13, 14] + canvas_tag: [] # e.g. "v2.6.1" + name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, macOS + runs-on: macos-latest + env: + CANVAS_VERSION_TO_BUILD: ${{ matrix.canvas_tag }} + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ matrix.canvas_tag }} + + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - name: Build + run: | + npm install -g node-gyp + npm install --ignore-scripts + . prebuild/macOS/preinstall.sh + cp prebuild/macOS/binding.gyp binding.gyp + node-gyp rebuild -j 2 + . prebuild/macOS/bundle.sh + + - name: Test binary + run: | + brew uninstall --force cairo pango librsvg giflib harfbuzz + npm test + + - name: Make bundle + id: make_bundle + run: . prebuild/tarball.sh + + - name: Upload + uses: actions/github-script@0.9.0 + with: + script: | + const fs = require("fs"); + const assetName = "${{ steps.make_bundle.outputs.asset_name }}"; + const tagName = process.env.UPLOAD_TO || process.env.CANVAS_VERSION_TO_BUILD; + const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); + + const releases = await github.repos.listReleases({owner, repo}); + const release = releases.data.find(r => r.tag_name === tagName); + if (!release) + throw new Error(`Tag ${tagName} not found. Did you make the GitHub release?`); + + const oldAsset = release.assets.find(a => a.name === assetName); + if (oldAsset) + await github.repos.deleteReleaseAsset({owner, repo, asset_id: oldAsset.id}); + + // (This is equivalent to actions/upload-release-asset. We're + // already in a script, so might as well do it here.) + const r = await github.repos.uploadReleaseAsset({ + url: release.upload_url, + headers: { + "content-type": "application/x-gzip", + "content-length": `${fs.statSync(assetName).size}` + }, + name: assetName, + data: fs.readFileSync(assetName) + }); + + Win: + strategy: + matrix: + node: [8, 9, 10, 11, 12, 13, 14] + canvas_tag: [] # e.g. "v2.6.1" + name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, Windows + runs-on: windows-latest + env: + CANVAS_VERSION_TO_BUILD: ${{ matrix.canvas_tag }} + steps: + # TODO drop when https://github.com/actions/virtual-environments/pull/632 lands + - uses: numworks/setup-msys2@v1 + with: + update: true + path-type: inherit + + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - uses: actions/checkout@v2 + with: + ref: ${{ matrix.canvas_tag }} + + - name: Build + run: | + npm install -g node-gyp + npm install --ignore-scripts + msys2do . prebuild/Windows/preinstall.sh + msys2do cp prebuild/Windows/binding.gyp binding.gyp + msys2do node-gyp configure + msys2do node-gyp rebuild -j 2 + + - name: Bundle + run: msys2do . prebuild/Windows/bundle.sh + + - name: Test binary + # By not running in msys2, this doesn't have access to the msys2 libs + run: npm test + + - name: Make asset + id: make_bundle + # I can't figure out why this isn't an env var already. It shows up with `env`. + run: msys2do UPLOAD_TO=${{ env.UPLOAD_TO }} CANVAS_VERSION_TO_BUILD=${{ env.CANVAS_VERSION_TO_BUILD}} . prebuild/tarball.sh + + - name: Upload + uses: actions/github-script@0.9.0 + with: + script: | + const fs = require("fs"); + const assetName = "${{ steps.make_bundle.outputs.asset_name }}"; + const tagName = process.env.UPLOAD_TO || process.env.CANVAS_VERSION_TO_BUILD; + const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); + + const releases = await github.repos.listReleases({owner, repo}); + const release = releases.data.find(r => r.tag_name === tagName); + if (!release) + throw new Error(`Tag ${tagName} not found. Did you make the GitHub release?`); + + const oldAsset = release.assets.find(a => a.name === assetName); + if (oldAsset) + await github.repos.deleteReleaseAsset({owner, repo, asset_id: oldAsset.id}); + + // (This is equivalent to actions/upload-release-asset. We're + // already in a script, so might as well do it here.) + const r = await github.repos.uploadReleaseAsset({ + url: release.upload_url, + headers: { + "content-type": "application/x-gzip", + "content-length": `${fs.statSync(assetName).size}` + }, + name: assetName, + data: fs.readFileSync(assetName) + }); diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ff743123..c3743b77a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ project adheres to [Semantic Versioning](http://semver.org/). ================== ### Changed * Switch CI to Github Actions. (Adds Windows and macOS builds.) +* Switch prebuilds to GitHub actions in the Automattic/node-canvas repository. + Previously these were in the [node-gfx/node-canvas-prebuilt](https://github.com/node-gfx/node-canvas-prebuilt) + and triggered manually. ### Added * Export `rsvgVersion`. ### Fixed diff --git a/package.json b/package.json index 40243ec2f..cc5f89d13 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "binary": { "module_name": "canvas", "module_path": "build/Release", - "host": "https://github.com/node-gfx/node-canvas-prebuilt/releases/download/", + "host": "https://github.com/Automattic/node-canvas/releases/download/", "remote_path": "v{version}", "package_name": "{module_name}-v{version}-{node_abi}-{platform}-{libc}-{arch}.tar.gz" }, diff --git a/prebuild/Linux/binding.gyp b/prebuild/Linux/binding.gyp new file mode 100644 index 000000000..1a967667d --- /dev/null +++ b/prebuild/Linux/binding.gyp @@ -0,0 +1,53 @@ +{ + 'targets': [ + { + 'target_name': 'canvas', + 'sources': [ + 'src/backend/Backend.cc', + 'src/backend/ImageBackend.cc', + 'src/backend/PdfBackend.cc', + 'src/backend/SvgBackend.cc', + 'src/bmp/BMPParser.cc', + 'src/Backends.cc', + 'src/Canvas.cc', + 'src/CanvasGradient.cc', + 'src/CanvasPattern.cc', + 'src/CanvasRenderingContext2d.cc', + 'src/closure.cc', + 'src/color.cc', + 'src/Image.cc', + 'src/ImageData.cc', + 'src/init.cc', + 'src/register_font.cc' + ], + 'defines': [ + 'HAVE_GIF', + 'HAVE_JPEG', + 'HAVE_RSVG' + ], + 'libraries': [ + ' /dev/null 2>&1 || { + echo "could not find lib$lib.dll, have to skip "; + continue; + } + + dlltool -d lib$lib.def -l /mingw64/lib/lib$lib.lib > /dev/null 2>&1 || { + echo "could not create dll for lib$lib.dll"; + continue; + } + + echo "created lib$lib.lib from lib$lib.dll"; + + rm lib$lib.def +done diff --git a/prebuild/macOS/binding.gyp b/prebuild/macOS/binding.gyp new file mode 100644 index 000000000..00ae2ccbc --- /dev/null +++ b/prebuild/macOS/binding.gyp @@ -0,0 +1,51 @@ +{ + 'targets': [ + { + 'target_name': 'canvas', + 'sources': [ + 'src/backend/Backend.cc', + 'src/backend/ImageBackend.cc', + 'src/backend/PdfBackend.cc', + 'src/backend/SvgBackend.cc', + 'src/bmp/BMPParser.cc', + 'src/Backends.cc', + 'src/Canvas.cc', + 'src/CanvasGradient.cc', + 'src/CanvasPattern.cc', + 'src/CanvasRenderingContext2d.cc', + 'src/closure.cc', + 'src/color.cc', + 'src/Image.cc', + 'src/ImageData.cc', + 'src/init.cc', + 'src/register_font.cc' + ], + 'defines': [ + 'HAVE_GIF', + 'HAVE_JPEG', + 'HAVE_RSVG' + ], + 'libraries': [ + '