From 86a848bc43d720f35b0848e0b7e6c0972539c354 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Thu, 30 Nov 2023 12:17:34 -0600 Subject: [PATCH] delete nu and bash scripts, polish up TS one --- tools/api-diff.nu | 64 ---------------------------------- tools/api-diff.sh | 51 --------------------------- tools/deno/api-diff.ts | 78 +++++++++++++++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 132 deletions(-) delete mode 100755 tools/api-diff.nu delete mode 100755 tools/api-diff.sh diff --git a/tools/api-diff.nu b/tools/api-diff.nu deleted file mode 100755 index 0c81738d10..0000000000 --- a/tools/api-diff.nu +++ /dev/null @@ -1,64 +0,0 @@ -#! /usr/bin/env nu - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# Copyright Oxide Computer Company - -def genForCommit [commit: string, force: bool] { - let tmpDir = $"/tmp/api-diff/($commit)" - - # if the directory already exists and we haven't passed the force flag, - # don't bother downloading and generating it again - if (($tmpDir | path exists) and (not $force)) { return } - - rm -rf $tmpDir - mkdir $tmpDir - npm run --silent --prefix ../oxide.ts gen-from $commit $tmpDir - npx prettier --write --log-level error $tmpDir -} - -if (which gh | is-empty) { - error make {msg: 'gh is not installed'} -} - -def promptForPr [] { - (gh pr list --repo oxidecomputer/omicron --limit 100 --json number,title,updatedAt,author - --template '{{range .}}{{tablerow .number .title .author.name (timeago .updatedAt)}}{{end}}' ) | - fzf --height 25% --reverse | - cut -f1 -d ' ' -} - -# Visualize API changes for an Omicron PR by generating and diffing the TS -# client before and after the change -def main [ - prNum?: int # If left out, interactive picker will be shown - --force # Download and generate even if output already present -] { - let prNum = if ($prNum == null) { - promptForPr - } else { - $prNum - } - - let query = $"query={ - repository\(owner: \"oxidecomputer\", name: \"omicron\") { - pullRequest\(number: ($prNum)) { - baseRefOid - headRefOid - } - } - }" - - let pr = (gh api graphql -f $query | from json | get data.repository.pullRequest) - - let base = $pr | get baseRefOid - genForCommit $base $force - - let head = $pr | get headRefOid - genForCommit $head $force - - # git difftool is a trick to diff with whatever you have git set to use - git --no-pager difftool $"/tmp/api-diff/($base)/Api.ts" $"/tmp/api-diff/($head)/Api.ts" -} diff --git a/tools/api-diff.sh b/tools/api-diff.sh deleted file mode 100755 index 24584b5158..0000000000 --- a/tools/api-diff.sh +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/env bash - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# Copyright Oxide Computer Company - -function genForCommit() { - COMMIT=$1 - TMP_DIR="/tmp/api-diff/$COMMIT" - rm -rf $TMP_DIR - mkdir -p $TMP_DIR - npm run --silent --prefix ../oxide.ts gen-from $COMMIT $TMP_DIR - npx prettier --write --log-level error $TMP_DIR -} - -if ! command -v gh &> /dev/null; then - echo "Error: gh is not installed." >&2 - exit 1 -fi - -PR_NUM=$( - gh pr list -R oxidecomputer/omicron --limit 100 --json number,title,updatedAt,author \ - --template '{{range .}}{{tablerow .number .title .author.name (timeago .updatedAt)}}{{end}}' | - fzf --height 25% --reverse | - cut -f1 -d ' ' -) - -if ! [[ "$PR_NUM" =~ ^[0-9]+$ ]]; then - echo "Error picking PR. Expected number, got $PR_NUM" >&2 - exit 1 -fi - -PR_JSON=$(gh api graphql -f query="{ - repository(owner: \"oxidecomputer\", name: \"omicron\") { - pullRequest(number: $PR_NUM) { - baseRefOid - headRefOid - } - } -}" | jq -r '.data.repository.pullRequest') - -BASE=$(echo $PR_JSON | jq -r '.baseRefOid') -genForCommit $BASE - -HEAD=$(echo $PR_JSON | jq -r '.headRefOid') -genForCommit $HEAD - -# git difftool is a trick to diff with whatever you have git set to use -git --no-pager difftool "/tmp/api-diff/$BASE/Api.ts" "/tmp/api-diff/$HEAD/Api.ts" || true diff --git a/tools/deno/api-diff.ts b/tools/deno/api-diff.ts index 9621255b86..df2b809ff3 100755 --- a/tools/deno/api-diff.ts +++ b/tools/deno/api-diff.ts @@ -7,8 +7,28 @@ * * Copyright Oxide Computer Company */ +import * as flags from 'https://deno.land/std@0.208.0/flags/mod.ts' +import { exists } from 'https://deno.land/std@0.208.0/fs/mod.ts' import { $, CommandBuilder } from 'https://deno.land/x/dax@0.35.0/mod.ts' +const HELP = ` +Display changes to API client caused by a given Omicron PR. Works by downloading +the OpenAPI spec before and after, generating clients in temp dirs, and diffing. + +Requirements: + - Deno (which you have if you're seeing this message) + - GitHub CLI (gh) + +Usage: + ./tools/deno/api-diff.ts [options] + +PR number is optional. If left out, interactive picker is shown. + +Options: + -f, --force Download spec and regen client even if dir already exists + -h, --help Show this help message +`.trim() + // inspired by: https://github.com/dsherret/dax/issues/137#issuecomment-1603848769 declare module 'https://deno.land/x/dax@0.35.0/mod.ts' { interface CommandBuilder { @@ -25,32 +45,46 @@ CommandBuilder.prototype.pipe = function (next: CommandBuilder): CommandBuilder // my stupid bash function to show up here. I'm sure it's possible async function pickPr() { const listPRs = () => - $`gh pr list -R oxidecomputer/omicron --limit 100 --json number,title,updatedAt,author --template '{{range .}}{{tablerow .number .title .author.name (timeago .updatedAt)}}{{end}}'` + $`gh pr list -R oxidecomputer/omicron --limit 100 + --json number,title,updatedAt,author + --template '{{range .}}{{tablerow .number .title .author.name (timeago .updatedAt)}}{{end}}'` const picker = () => $`fzf --height 25% --reverse` const cut = () => $`cut -f1 -d ' '` - return listPRs().pipe(picker()).pipe(cut()).text() + const prNum = await listPRs().pipe(picker()).pipe(cut()).text() + if (!/^\d+$/.test(prNum)) { + console.error(`Error picking PR. Expected number, got '${prNum}'`) + Deno.exit() + } + return parseInt(prNum, 10) } -async function getPrRange(prNum: string) { - const pr = await $`gh api graphql -f query='{ - repository(owner: "oxidecomputer", name: "omicron") { - pullRequest(number: ${prNum}) { +async function getPrRange(prNum: number) { + const query = `{ + repository(owner: "oxidecomputer", name: "omicron") { + pullRequest(number: ${prNum}) { baseRefOid headRefOid } } - }'`.json() + }` + const pr = await $`gh api graphql -f query=${query}`.json() const { baseRefOid: base, headRefOid: head } = pr.data.repository.pullRequest return { base, head } as { base: string; head: string } } -async function genForCommit(commit: string) { +async function genForCommit(commit: string, force: boolean) { const tmpDir = `/tmp/api-diff/${commit}` - await $`rm -rf ${tmpDir}` - await $`mkdir -p ${tmpDir}` - await $`npm run --silent --prefix ../oxide.ts gen-from ${commit} ${tmpDir}` - await $`npx prettier --write --log-level error ${tmpDir}` + const alreadyExists = await exists(tmpDir) + + // if the directory already exists, skip it + if (force || !alreadyExists) { + await $`rm -rf ${tmpDir}` + await $`mkdir -p ${tmpDir}` + await $`npm run --silent --prefix ../oxide.ts gen-from ${commit} ${tmpDir}` + await $`npx prettier --write --log-level error ${tmpDir}` + } + return tmpDir } @@ -60,17 +94,27 @@ async function genForCommit(commit: string) { if (!$.commandExistsSync('gh')) throw Error('Need gh (GitHub CLI)') -const prNum = await pickPr() +const args = flags.parse(Deno.args, { + alias: { force: ['f'], h: 'help' }, + boolean: ['force', 'help'], +}) + +if (args.help) { + console.log(HELP) + Deno.exit() +} + +const prNum = args._[0] ? args._[0] : await pickPr() -if (!/^\d+$/.test(prNum)) { - console.error(`Error picking PR. Expected number, got '${prNum}'`) +if (typeof prNum !== 'number') { + console.error(`PR number must be a number. Got '${prNum}' instead.`) Deno.exit() } const { base, head } = await getPrRange(prNum) -const tmpDirBase = await genForCommit(base) -const tmpDirHead = await genForCommit(head) +const tmpDirBase = await genForCommit(base, args.force) +const tmpDirHead = await genForCommit(head, args.force) // git difftool is a trick to diff with whatever you have git set to use await $`git --no-pager difftool ${tmpDirBase}/Api.ts ${tmpDirHead}/Api.ts || true`