Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,19 +209,23 @@ jobs:
run: |
cmake --preset linux-opengl-node -DCMAKE_BUILD_TYPE=${{ env.BUILDTYPE }}

- name: Get vcpkg commit id
- name: "Create directory '${{ github.workspace }}/platform/windows/vendor/vcpkg/bincache' (Windows)"
if: runner.os == 'Windows'
shell: pwsh
run: |
$vcpkg_commit_id = ($(git submodule status .\platform\windows\vendor\vcpkg).Trim() -split ' ')[0]
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_COMMIT_ID=${vcpkg_commit_id}"
run: mkdir -p ${{ github.workspace }}/platform/windows/vendor/vcpkg/bincache
shell: bash

- name: Restore vcpkg binary cache
- name: Restore vcpkg cache (Windows)
if: runner.os == 'Windows'
uses: actions/cache/restore@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ${{ github.workspace }}\platform\windows\vendor\vcpkg\archives
key: vcpkg-${{ env.VCPKG_COMMIT_ID }}
path: |
${{ github.workspace }}/platform/windows/vendor/vcpkg
!${{ github.workspace }}/platform/windows/vendor/vcpkg/buildtrees
!${{ github.workspace }}/platform/windows/vendor/vcpkg/packages
!${{ github.workspace }}/platform/windows/vendor/vcpkg/downloads
!${{ github.workspace }}/platform/windows/vendor/vcpkg/installed
key: |
${{ matrix.runs-on }}-${{ env.BUILDTYPE }}-${{ github.job }}-${{ hashFiles( '.git/modules/platform/windows/vendor/vcpkg/HEAD' ) }}-${{ hashFiles( 'platform/windows/Get-VendorPackages.ps1' ) }}

- name: Configure maplibre-native (Windows x64)
if: runner.os == 'Windows' && matrix.arch == 'x86_64'
Expand Down Expand Up @@ -251,6 +255,10 @@ jobs:
run: |
cmake --build build

- name: Create prebuilt binary tarballs
working-directory: platform/node
run: npm run package-binaries

- name: Run render tests on macOS
id: render_tests
if: runner.os == 'macOS'
Expand Down
100 changes: 58 additions & 42 deletions .github/workflows/node-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ jobs:
release-check:
name: Check if version is published
runs-on: ubuntu-latest
permissions:
contents: write
defaults:
run:
shell: bash
Expand All @@ -17,22 +19,47 @@ jobs:
with:
persist-credentials: false

- name: Use Node.js from nvmrc
- name: Use Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v4
with:
node-version-file: 'platform/node/.nvmrc'

- name: npm ci
working-directory: platform/node
run: npm ci --ignore-scripts

- name: Check if version is published
id: check
working-directory: platform/node
run: |
packageName="$( node -e "console.log(require('./package.json').name)" )"
currentVersion="$( node -e "console.log(require('./package.json').version)" )"
isPublished="$( npm view @maplibre/maplibre-gl-native versions --json | jq -c --arg cv "$currentVersion" 'any(. == $cv)' )"
echo "published=$isPublished" >> "$GITHUB_OUTPUT"
isPublished="$( npm view "$packageName" versions --json | jq -c --arg cv "$currentVersion" 'any(. == $cv)' )"
isPrerelease="$( node -e "console.log(require('semver').prerelease('$currentVersion') ? 'true' : 'false')" )"
{
echo "published=$isPublished"
echo "current-version=$currentVersion"
echo "prerelease=$isPrerelease"
echo "package-name=$packageName"
} >> "$GITHUB_OUTPUT"
echo "currentVersion: $currentVersion"
echo "isPublished: $isPublished"
echo "isPrerelease: $isPrerelease"
echo "packageName: $packageName"

- name: Create Git Tag
if: ${{ steps.check.outputs.published == 'false' }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag node-v${{ steps.check.outputs.current-version }}
git push origin node-v${{ steps.check.outputs.current-version }}

outputs:
published: ${{ steps.check.outputs.published }}
current-version: ${{ steps.check.outputs.current-version }}
prerelease: ${{ steps.check.outputs.prerelease }}
package-name: ${{ steps.check.outputs.package-name }}

publish_binaries:
needs: release-check
Expand Down Expand Up @@ -182,6 +209,9 @@ jobs:
- name: Get vcpkg commit id
if: runner.os == 'Windows'
shell: pwsh
env:
VCPKG_INSTALL_OPTIONS: "--debug"
VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}\\platform\\windows\\vendor\\vcpkg\\archives,readwrite"
run: |
$vcpkg_commit_id = ($(git submodule status .\platform\windows\vendor\vcpkg).Trim() -split ' ')[0]
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_COMMIT_ID=${vcpkg_commit_id}"
Expand Down Expand Up @@ -221,29 +251,24 @@ jobs:
run: |
cmake --build build

- name: Publish X64 Release to Github
if: matrix.arch == 'x86_64'
- name: Create prebuilt binary tarballs
working-directory: platform/node
env:
PUBLISH: true
BUILDTYPE: RelWithDebInfo
NODE_PRE_GYP_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./scripts/publish.sh
run: npm run package-binaries

- name: Publish ARM Release to Github
if: matrix.arch == 'arm64'
working-directory: platform/node
- name: Upload Release Assets
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # 2.3.3
with:
tag_name: node-v${{ needs.release-check.outputs.current-version }}
name: node-v${{ needs.release-check.outputs.current-version }}
files: platform/node/*.tar.gz
draft: true
prerelease: ${{ needs.release-check.outputs.prerelease == 'true' }}
env:
PUBLISH: true
BUILDTYPE: RelWithDebInfo
NODE_PRE_GYP_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./scripts/publish.sh --target_arch=arm64
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

publish_npm:
runs-on: ubuntu-latest
needs: publish_binaries
needs: [release-check, publish_binaries]
permissions:
contents: write
defaults:
Expand All @@ -260,31 +285,22 @@ jobs:
with:
node-version-file: 'platform/node/.nvmrc'

- name: Get version
id: package-version
uses: martinbeentjes/npm-get-version-action@3cf273023a0dda27efcd3164bdfb51908dd46a5b # v1.3.1
with:
path: platform/node

- name: npm ci
working-directory: platform/node
run: npm ci --ignore-scripts

- name: Prepare release
id: prepare_release
working-directory: platform/node
run: |
RELEASE_TYPE="$(node -e "console.log(require('semver').prerelease('${{ steps.package-version.outputs.current-version }}') ? 'prerelease' : 'regular')")"
if [[ $RELEASE_TYPE == 'regular' ]]; then
echo "prerelease=false" >> "$GITHUB_OUTPUT"
else
echo "prerelease=true" >> "$GITHUB_OUTPUT"
fi

- name: Extract changelog for version
working-directory: platform/node
run: |
awk '/^##/ { p = 0 }; p == 1 { print }; $0 == "## ${{ steps.package-version.outputs.current-version }}" { p = 1 };' CHANGELOG.md > changelog_for_version.md
# Extract changelog and ensure file exists
awk '/^##/ { p = 0 }; p == 1 { print }; $0 == "## ${{ needs.release-check.outputs.current-version }}" { p = 1 };' CHANGELOG.md > changelog_for_version.md
# Check if changelog was extracted successfully
if [[ ! -s changelog_for_version.md ]]; then
echo "No changelog found for version ${{ needs.release-check.outputs.current-version }}"
echo "## Changes" > changelog_for_version.md
echo "Release notes will be added later." >> changelog_for_version.md
fi
echo "Changelog content:"
cat changelog_for_version.md

- name: Update Release Notes
Expand All @@ -293,15 +309,15 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: node-v${{ steps.package-version.outputs.current-version }}
name: node-v${{ steps.package-version.outputs.current-version }}
tag: node-v${{ needs.release-check.outputs.current-version }}
name: node-v${{ needs.release-check.outputs.current-version }}
bodyFile: platform/node/changelog_for_version.md
allowUpdates: true
draft: true
prerelease: ${{ steps.prepare_release.outputs.prerelease }}

- name: Publish to NPM (release)
if: ${{ steps.prepare_release.outputs.prerelease == 'false' }}
if: ${{ needs.release-check.outputs.prerelease == 'false' }}
working-directory: platform/node
run: |
npm config set //registry.npmjs.org/:_authToken "${NPM_TOKEN}"
Expand All @@ -310,7 +326,7 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_ORG_TOKEN }}

- name: Publish to NPM (prerelease)
if: ${{ steps.prepare_release.outputs.prerelease == 'true' }}
if: ${{ needs.release-check.outputs.prerelease == 'true' }}
working-directory: platform/node
run: |
npm config set //registry.npmjs.org/:_authToken "${NPM_TOKEN}"
Expand Down
142 changes: 142 additions & 0 deletions platform/node/package-binaries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const tar = require('tar');

// Read package.json
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));

// Get platform and architecture mappings
function getPlatform() {
// Use Node.js built-in process.platform
switch (process.platform) {
case 'linux':
return 'linux';
case 'darwin':
return 'darwin';
case 'win32':
return 'win32';
default:
console.warn(`Unknown platform: ${process.platform}, using as-is`);
return process.platform;
}
}

function getArch() {
// Use Node.js built-in process.arch
switch (process.arch) {
case 'x64':
return 'x64';
case 'arm64':
return 'arm64';
case 'ia32':
return 'ia32';
case 'arm':
return 'arm';
case 's390x':
return 's390x';
case 'ppc64':
return 'ppc64';
default:
console.warn(`Unknown architecture: ${process.arch}, using as-is`);
return process.arch;
}
}

// Clean package name for filename
function cleanPackageName(name) {
let cleanName = name;
// If it's a scoped package, get the part after the last slash
if (cleanName.includes('/')) {
cleanName = cleanName.split('/').pop();
}
// Sanitize the name by removing all @ and / characters
return cleanName.replace(/[@\/]/g, '-');
}

// Create tarballs for each ABI
async function createTarballs() {
const platform = getPlatform();
const arch = getArch();
const version = packageJson.version;
const cleanName = cleanPackageName(packageJson.name);

console.log(`Creating tarballs for platform: ${platform}, arch: ${arch}, version: ${version}`);

// Find all ABI directories
const libDir = './lib';
if (!fs.existsSync(libDir)) {
console.error(`lib directory not found: ${libDir}`);
process.exit(1);
}

const abiDirs = fs.readdirSync(libDir)
.filter(dir => dir.startsWith('node-v') && fs.statSync(path.join(libDir, dir)).isDirectory())
.filter(dir => fs.existsSync(path.join(libDir, dir, 'mbgl.node')));

if (abiDirs.length === 0) {
console.error('No ABI directories with mbgl.node found');
process.exit(1);
}

console.log(`Found ABI directories: ${abiDirs.join(', ')}`);

const createdTarballs = [];

for (const abiDir of abiDirs) {
const abi = abiDir.replace('node-v', '');
const tarballName = `${cleanName}-v${version}-node-v${abi}-${platform}-${arch}.tar.gz`;
const binaryPath = path.join('lib', abiDir, 'mbgl.node');

console.log(`Creating tarball: ${tarballName}`);
console.log(` Platform: ${platform}, Arch: ${arch}, ABI: ${abi}`);
console.log(` Binary: ${binaryPath}`);

try {
// Create tarball preserving the lib/node-v[abi]/mbgl.node structure
await tar.create({
gzip: true,
file: tarballName,
cwd: '.',
}, [binaryPath]);

// Verify tarball was created and get its size
const stats = fs.statSync(tarballName);
console.log(` Tarball created successfully (${stats.size} bytes)`);
if (stats.size === 0) {
throw new Error('Tarball is empty');
}
createdTarballs.push(tarballName);
} catch (error) {
console.error(`Failed to create tarball ${tarballName}:`, error.message);
process.exit(1);
}
}
console.log(`\nSuccessfully created ${createdTarballs.length} tarballs:`);
createdTarballs.forEach(tarball => {
const stats = fs.statSync(tarball);
console.log(` ${tarball} (${stats.size} bytes)`);
});
return createdTarballs;
}

// Main execution
if (require.main === module) {
createTarballs()
.then(() => {
console.log('Tarball creation completed successfully');
process.exit(0);
})
.catch(error => {
console.error('Error creating tarballs:', error);
process.exit(1);
});
}

module.exports = {
createTarballs,
getPlatform,
getArch,
cleanPackageName
};
Loading
Loading