Skip to content

Commit

Permalink
Download artifacts and copy to dist
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Jan 5, 2025
1 parent 0e01904 commit d72ebc4
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 38 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,28 @@ jobs:
with:
files: dist/*.dawn.node

package:
needs: build
name: package
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Print env
run: |
echo github.event.action: ${{ github.event.action }}
echo github.event_name: ${{ github.event_name }}
- name: Build
shell: download-and-package
run: |
npm ci
node build/download-run-artifacts.js "--repo=${{ github.repository }}" "--run_id=${{ github.run_id }}""
105 changes: 105 additions & 0 deletions build/download-run-artifacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import fs from 'node:fs';
import path from 'node:path';
import {unzip} from 'unzipit';

import * as github from './github.js';
import {
parseArgs,
} from './utils.js'

async function downloadFileFromZip(url, filepath) {
const res = await fetch(url);
const zipData = await res.arrayBuffer();
const {entries} = await unzip(zipData);
return Promise.all(Object.entries(entries).map(async ([name, entry]) => {
const data = await entry.arrayBuffer();
const filename = path.join(filepath, name);
console.log('downloaded:', filename);
fs.mkdirSync(filepath, {recursive: true});
fs.writeFileSync(filename, new Uint8Array(data));
return filename;
}));
}

const options = {
repo: { type: 'string', inlineValue: true, required: true, description: 'owner/name of repo' },
run_id: { type: 'string', inlineValue: true, required: true, description: 'run_id from action' },
};
const { values: args } = parseArgs({ args: process.argv.slice(2), options });

/*
const data = {
"total_count": 3,
"artifacts": [
{
"id": 2386423695,
"node_id": "MDg6QXJ0aWZhY3QyMzg2NDIzNjk1",
"name": "darwin-arm64.dawn.node",
"size_in_bytes": 10841703,
"url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386423695",
"archive_download_url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386423695/zip",
"expired": false,
"created_at": "2025-01-04T23:01:06Z",
"updated_at": "2025-01-04T23:01:06Z",
"expires_at": "2025-04-04T22:49:48Z",
"workflow_run": {
"id": 12614358725,
"repository_id": 911859581,
"head_repository_id": 911859581,
"head_branch": "main",
"head_sha": "3bb7a9fec4559ddc789c424b92a92122ad09c1f4"
}
},
{
"id": 2386431784,
"node_id": "MDg6QXJ0aWZhY3QyMzg2NDMxNzg0",
"name": "linux-x64.dawn.node",
"size_in_bytes": 120766916,
"url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386431784",
"archive_download_url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386431784/zip",
"expired": false,
"created_at": "2025-01-04T23:08:23Z",
"updated_at": "2025-01-04T23:08:23Z",
"expires_at": "2025-04-04T22:49:48Z",
"workflow_run": {
"id": 12614358725,
"repository_id": 911859581,
"head_repository_id": 911859581,
"head_branch": "main",
"head_sha": "3bb7a9fec4559ddc789c424b92a92122ad09c1f4"
}
},
{
"id": 2386436118,
"node_id": "MDg6QXJ0aWZhY3QyMzg2NDM2MTE4",
"name": "win32-x64.dawn.node",
"size_in_bytes": 11265694,
"url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386436118",
"archive_download_url": "https://api.github.com/repos/greggman/node-webgpu/actions/artifacts/2386436118/zip",
"expired": false,
"created_at": "2025-01-04T23:12:55Z",
"updated_at": "2025-01-04T23:12:55Z",
"expires_at": "2025-04-04T22:49:48Z",
"workflow_run": {
"id": 12614358725,
"repository_id": 911859581,
"head_repository_id": 911859581,
"head_branch": "main",
"head_sha": "3bb7a9fec4559ddc789c424b92a92122ad09c1f4"
}
}
]
}
*/

const [owner, repo] = args.repo.split('/');
const data = await github.getRunArtifacts({
owner,
repo,
run_id: args.run_id,
});
const filenames = await Promise.all(
data.artifacts
.filter(({name}) => name?.endsWith('.node'))
.map(({archive_download_url}) => downloadFileFromZip(archive_download_url, 'dist'))
);
24 changes: 21 additions & 3 deletions build/github.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
export async function getLatestRelease({owner, repo}) {
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`, {
function fail(msg) {
throw new Error(msg);
}

async function fetchGithub(url, params) {
url = `https://api.github.com/${url.replaceAll(/\{(.*?)\}/g, (_, id) => params[id] ?? fail(`no: ${id}`))}`;
console.log(url);
const res = await fetch(url, {
headers: {
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
}
},
});
return await res.json();
}

export async function getLatestRelease(params) {
return fetchGithub('repos/{owner}/{repo}/releases/latest', params);
}

export async function getLatestArtifacts(params) {
return fetchGithub('repos/{owner}/{repo}/actions/artifacts', params);
}

export async function getRunArtifacts(params) {
return fetchGithub('repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', params);
}
20 changes: 2 additions & 18 deletions build/publish.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import path from 'path';
import fs from 'fs';


import {execute} from './execute.js';
import * as github from './github.js';
Expand All @@ -12,27 +11,12 @@ function executeL(cmd, args) {
execute(cmd, args);
}

async function downloadFile(name, url, filepath) {
const res = await fetch(url);
const data = await res.arrayBuffer();
const filename = path.join(filepath, name);
console.log('download:', filename);
fs.mkdirSync(filepath, {recursive: true});
fs.writeFileSync(filename, new Uint8Array(data));
return filename;
}

async function main() {
const data = await github.getLatestRelease({
owner,
repo,
});
//const vsixFilenames = await Promise.all(
// data.assets
// .filter(({name}) => name?.endsWith('.vsix'))
// .map(({name, browser_download_url}) => downloadFile(name, browser_download_url, 'dist'))
//);
//executeL('./node_modules/.bin/vsce', ['publish', '--packagePath', ...vsixFilenames]);
executeL('./node_modules/.bin/vsce', ['publish', '--packagePath', ...vsixFilenames]);
}

main();
37 changes: 35 additions & 2 deletions build/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import fs from 'node:fs';
import path from 'node:path';
import util from 'node:util';

export function exists(filename) {
try {
Expand All @@ -24,4 +25,36 @@ export function appendPathIfItExists(filepath) {

export function addElemIf(cond, elem) {
return cond ? [elem] : [];
}

function formatOption(key, { type, inlineValue }) {
return type === 'bool'
? `--${key}`
: inlineValue
? `--${key}=value`
: `--${key} value`;
}

export function showHelp(options) {
const longest = Object.entries(options).reduce((max, [k, v]) => Math.max(max, formatOption(k, v).length), 0);
const help = Object.entries(options).map(([k, v]) => `${formatOption(k, v).padEnd(longest + 1)} : ${v.description ?? ''}`);
console.log(help.join('\n'));
}

export function parseArgs({options, args}) {
const { values, positionals } = util.parseArgs({ args, options });
for (const [k, {required}] of Object.entries(options)) {
if (required && values[k] === undefined) {
console.error(`missing required option: ${k}`);
showHelp(options);
process.exit(1);
}
}
const ndx = positionals.findIndex(v => v.startsWith('-'));
if (ndx >= 0) {
console.error(`unknown option: ${positionals[ndx]}`);
showHelp(options);
process.exit(1);
}
return { values, positionals };
}
9 changes: 9 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const __dirname = dirname(fileURLToPath(import.meta.url));
const dawnNodePath = join(__dirname, `${process.platform}-${process.arch}.node`);
const { create, globals } = require(dawnNodePath);
export { create, globals }
21 changes: 20 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@
"url": "https://github.com/greggman/node-webgpu/issues"
},
"homepage": "https://github.com/greggman/node-webgpu#readme",
"files": [
"dist/**/*",
"index.js"
],
"devDependencies": {
"mocha": "^11.0.1"
"mocha": "^11.0.1",
"unzipit": "^1.4.3"
}
}
19 changes: 17 additions & 2 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import Mocha from 'mocha';

const mocha = new Mocha({
});
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const isDev = process.argv[2] !== 'dev';
const isWin = process.platform === 'win32';
const dawnNodePath = isDev
? isWin
? `${process.cwd()}/third_party/dawn/out/cmake-release/Debug/dawn.node`
: `${process.cwd()}/third_party/dawn/out/cmake-release/dawn.node`
: `${process.cwd()}/dist/${process.platform}-${process.arch}.node`;

const { create, globals } = require(dawnNodePath);

Object.assign(globalThis, globals);
globalThis.navigator = { gpu: create([]) };

const mocha = new Mocha({});

mocha.addFile('./test/tests/basic-tests.js');

Expand Down
11 changes: 0 additions & 11 deletions test/tests/basic-tests.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const isWin = process.platform === 'win32';
const dawnNodePath = isWin
? `${process.cwd()}/third_party/dawn/out/cmake-release/gen/node/NapiSymbols.def`.replaceAll('\\', '/')
: `${process.cwd()}/third_party/dawn/out/cmake-release/dawn.node`;

const { create, globals } = require(dawnNodePath);

Object.assign(globalThis, globals);
const navigator = { gpu: create([]) };

function assert(cond, msg = '') {
if (!cond) {
Expand Down

0 comments on commit d72ebc4

Please sign in to comment.