diff --git a/tools/package.json b/tools/package.json new file mode 100644 index 0000000000..1fc9b8cf28 --- /dev/null +++ b/tools/package.json @@ -0,0 +1,15 @@ +{ + "name": "webgpu-tools", + "version": "1.0.0", + "description": "Scripts to help WebGPU development", + "main": "extract-wgsl-agenda.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@octokit/rest": "^17.6.0", + "yargs": "^15.3.1" + } +} diff --git a/tools/wgsl-meeting-helper b/tools/wgsl-meeting-helper new file mode 100755 index 0000000000..6cb5273818 --- /dev/null +++ b/tools/wgsl-meeting-helper @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +const yargs = require("yargs"); +const { Octokit } = require("@octokit/rest"); + +// The identifier for the meeting discussion column in the WGSL project. +// You can list all the columns by calling this script with the "project-info" command. + +const WGSL_MEETING_COLUMN = 8898490; + +const TOKEN_ENV_NAME = "GPUWEB_GITHUB_TOKEN"; + +async function authenticate(token) { + const octokit = new Octokit({ auth: token }); + await octokit.request("/user"); + return octokit; +} + +async function agenda(kit, column) { + console.log("Suggested meeting agenda from Github project."); + console.log("----"); + const cards = await kit.projects.listCards({ column_id: column }); + for (let card of cards.data) { + // Notes are agenda topics that don't have an issue. + if (card.note) { + console.log(`- ${card.note}`); + } else { + // Check if the card is an issue. https://api.github.com/repos/gpuweb/gpuweb/issues/569 + const url = card.content_url; + const matches = /gpuweb\/gpuweb\/issues\/(\d+)$/.exec(url); + if (matches) { + const issueIdentifier = matches[1]; + const issue = await kit.issues.get({ owner: "gpuweb", repo: "gpuweb", issue_number: issueIdentifier }); + console.log(`- ${issue.data.title.replace(/\s*\[wgsl\]\s*/i, "")} (#${issueIdentifier})`); + console.log(` ${issue.data.html_url}`); + } + } + console.log(""); + } +} + +async function projectInfo(kit) { + const projects = await kit.projects.listForOrg({ org: "gpuweb" }); + for (let project of projects.data) { + console.log(`Columns for project "${project.name}" (id: ${project.id})`); + console.log("----"); + const columns = await kit.projects.listColumns({ project_id: project.id }); + for (let column of columns.data) { + console.log(`${column.name} (id: ${column.id})`); + } + console.log(""); + } +} + +const argumentProcessor = yargs + .scriptName("wgsl-meeting-helper") + .usage("$0 ") + .command({ + command: ["agenda", "$0"], + desc: "Build the meeting agenda from the WGSL Github Project.", + handler: () => { + run(agenda, WGSL_MEETING_COLUMN); + } + }) + .command({ + command: "project-info", + desc: "Build the meeting agenda from the WGSL Github Project.", + handler: () => { + run(projectInfo); + } + }) + .version(false) + .help() + .epilogue(`Requires a Github Personal Access Token to be provided as the environment variable ${TOKEN_ENV_NAME}.`) + +const token = process.env[TOKEN_ENV_NAME]; +if (!token) { + console.log("Error: missing Github Personal Access Token.\n"); + argumentProcessor.showHelp(); + process.exit(); +} + +async function run(targetFunction, ...args) { + const kit = await authenticate(token); + targetFunction(kit, ...args); +} + +argumentProcessor.parse(); +