Commit 4bae106
Changed files (15)
badges/star-gazer/star-gazer.ts
@@ -18,8 +18,14 @@ export default define({
}
if (selfStars.length >= 1) {
- grant('self-star', `I've starred ${selfStars.length} my own repositories.`)
- .evidence(selfStars.map((x) => `- <a href="${x.url}">${x.nameWithOwner}</a>`).join('\n'))
+ grant(
+ 'self-star',
+ `I've starred ${selfStars.length} my own repositories.`,
+ ).evidence(
+ selfStars
+ .map((x) => `- <a href="${x.url}">${x.nameWithOwner}</a>`)
+ .join('\n'),
+ )
}
},
})
scripts/megaera.mjs
@@ -1,5 +1,7 @@
import 'zx/globals'
-await $`megaera --schema .github/schema.graphql ${await glob('src/**/*.graphql')}`.verbose()
+await $({
+ verbose: true,
+})`megaera --schema .github/schema.graphql ${await glob('src/**/*.graphql')}`
await $`prettier --write ${await glob('src/**/*.graphql.ts')}`
echo(chalk.green('TypeScript files generated successfully.'))
src/context.ts
@@ -0,0 +1,137 @@
+import minimist from 'minimist'
+import { Octokit } from 'octokit'
+import { retry } from '@octokit/plugin-retry'
+import { throttling } from '@octokit/plugin-throttling'
+import path from 'node:path'
+import fs from 'node:fs'
+
+const CWD = process.cwd()
+const GIT_NAME = 'My Badges'
+const GIT_EMAIL = 'my-badges@users.noreply.github.com'
+const GIT_DIR = 'repo'
+const DATA_DIR = 'data'
+const BADGES_DIR = 'my-badges'
+const BADGES_DATAFILE = 'my-badges.json'
+
+export type Context = {
+ cwd: string
+ dataDir: string // used for data gathering
+ dataFile: string
+ dataTasks: string
+ gitDir: string // used for git operations
+ gitName: string
+ gitEmail: string
+ ghRepoOwner: string
+ ghRepoName: string
+ ghUser: string
+ ghToken: string
+ octokit: Octokit
+
+ dryrun: boolean
+ badgesCompact: boolean
+ badgesDatafile: string
+ badgesDir: string // badges output directory (relative to gitDir)
+ badgesSize: string | number
+ badgesPick: string[]
+ badgesOmit: string[]
+ taskName?: string
+ taskSkip: string
+ taskParams?: string
+}
+
+export function createCtx(
+ args: string[] = process.argv.slice(2),
+ env: Record<string, string | undefined> = process.env,
+): Context {
+ const argv = minimist(args, {
+ string: ['data', 'repo', 'token', 'size', 'user', 'pick', 'omit'],
+ boolean: ['dryrun', 'compact'],
+ })
+ const {
+ cwd: _cwd = CWD,
+ token: ghToken = env.GITHUB_TOKEN,
+ repo = env.GITHUB_REPO,
+ user: ghUser = argv._[0] || env.GITHUB_USER,
+ data,
+ size: badgesSize,
+ dryrun,
+ pick,
+ omit,
+ compact: badgesCompact,
+ task: taskName,
+ params: taskParams,
+ 'skip-task': taskSkip = '',
+ } = argv
+ const octokit = getOctokit(ghToken)
+ const cwd = path.resolve(_cwd)
+ const dataDir = path.resolve(cwd, DATA_DIR)
+ const dataFile = path.resolve(dataDir, data || `${ghUser}.json`)
+ const dataTasks = path.resolve(dataDir, `${ghUser}.tasks.json`)
+ const gitDir = path.resolve(cwd, GIT_DIR)
+ const badgesDir = path.resolve(gitDir, BADGES_DIR)
+ const badgesDatafile = path.resolve(badgesDir, data || BADGES_DATAFILE)
+ const [ghRepoOwner = '', ghRepoName = ''] = repo?.split('/', 2) || [
+ ghUser,
+ ghUser,
+ ]
+ const badgesPick = pick ? pick.split(',') : []
+ const badgesOmit = omit ? omit.split(',') : []
+
+ !fs.existsSync(dataDir) && fs.mkdirSync(dataDir, { recursive: true })
+ !fs.existsSync(gitDir) && fs.mkdirSync(gitDir, { recursive: true })
+
+ return {
+ cwd,
+ octokit,
+ gitName: GIT_NAME,
+ gitEmail: GIT_EMAIL,
+ gitDir,
+ ghUser,
+ ghToken,
+ ghRepoOwner,
+ ghRepoName,
+ dryrun,
+ badgesDir,
+ badgesDatafile,
+ badgesCompact,
+ badgesSize,
+ badgesOmit,
+ badgesPick,
+ dataDir,
+ dataFile,
+ dataTasks,
+ taskName,
+ taskParams,
+ taskSkip,
+ }
+}
+
+const MyOctokit = Octokit.plugin(retry, throttling)
+
+function getOctokit(token: string) {
+ return new MyOctokit({
+ auth: token,
+ log: console,
+ throttle: {
+ onRateLimit: (retryAfter, options: any, octokit, retryCount) => {
+ octokit.log.warn(
+ `Request quota exhausted for request ${options.method} ${options.url}`,
+ )
+ if (retryCount <= 3) {
+ octokit.log.info(`Retrying after ${retryAfter} seconds!`)
+ return true
+ }
+ },
+ onSecondaryRateLimit: (retryAfter, options: any, octokit, retryCount) => {
+ octokit.log.warn(
+ `SecondaryRateLimit detected for request ${options.method} ${options.url}`,
+ )
+ if (retryCount <= 3) {
+ octokit.log.info(`Retrying after ${retryAfter} seconds!`)
+ return true
+ }
+ },
+ },
+ retry: { doNotRetry: ['429'] },
+ })
+}
src/main.ts
@@ -1,125 +1,72 @@
#!/usr/bin/env node
+import fs from 'node:fs'
import allBadges from '#badges'
-import minimist from 'minimist'
-import { Octokit } from 'octokit'
-import { retry } from '@octokit/plugin-retry'
-import { throttling } from '@octokit/plugin-throttling'
import { presentBadges } from './present-badges.js'
-import { getUserBadges, gitPush, syncRepo, thereAreChanges } from './repo.js'
+import { getRepo } from './repo.js'
import { updateBadges } from './update-badges.js'
import { updateReadme } from './update-readme.js'
import { processTasks } from './process-tasks.js'
-import fs from 'node:fs'
import { Data } from './data.js'
+import { createCtx } from './context.js'
+import url from 'node:url'
-void (async function main() {
- try {
- const { env } = process
- const argv = minimist(process.argv.slice(2), {
- string: [
- 'data',
- 'repo',
- 'token',
- 'size',
- 'user',
- 'pick',
- 'omit',
- 'task',
- 'params',
- 'skip-task',
- ],
- boolean: ['dryrun', 'compact'],
+isMain() &&
+ main()
+ .then(() => process.exit(0))
+ .catch((err) => {
+ console.error(err)
+ process.exit(1)
})
- const {
- token = env.GITHUB_TOKEN,
- repo: repository = env.GITHUB_REPO,
- user: username = argv._[0] || env.GITHUB_USER,
- data: dataPath = '',
- size,
- dryrun,
- pick,
- omit,
- compact,
- task,
- params,
- 'skip-task': skipTask,
- } = argv
- const [owner, repo]: [string | undefined, string | undefined] =
- repository?.split('/', 2) || [username, username]
- const pickBadges = pick ? pick.split(',') : []
- const omitBadges = omit ? omit.split(',') : []
- const MyOctokit = Octokit.plugin(retry, throttling)
- const octokit = new MyOctokit({
- auth: token,
- log: console,
- throttle: {
- onRateLimit: (retryAfter, options: any, octokit, retryCount) => {
- octokit.log.warn(
- `Request quota exhausted for request ${options.method} ${options.url}`,
- )
- if (retryCount <= 3) {
- octokit.log.info(`Retrying after ${retryAfter} seconds!`)
- return true
- }
- },
- onSecondaryRateLimit: (
- retryAfter,
- options: any,
- octokit,
- retryCount,
- ) => {
- octokit.log.warn(
- `SecondaryRateLimit detected for request ${options.method} ${options.url}`,
- )
- if (retryCount <= 3) {
- octokit.log.info(`Retrying after ${retryAfter} seconds!`)
- return true
- }
- },
- },
- retry: { doNotRetry: ['429'] },
- })
+export async function main(
+ argv: string[] = process.argv.slice(2),
+ env: Record<string, string | undefined> = process.env,
+) {
+ const ctx = createCtx(argv, env)
+ const repo = getRepo(ctx)
+
+ repo.pull()
- if (owner && repo) syncRepo(owner, repo, token)
+ let data: Data
+ if (fs.existsSync(ctx.dataFile)) {
+ data = JSON.parse(fs.readFileSync(ctx.dataFile, 'utf8')) as Data
+ } else {
+ let ok: boolean
+ ;[ok, data] = await processTasks(ctx)
- let data: Data
- if (dataPath !== '') {
- data = JSON.parse(fs.readFileSync(dataPath, 'utf8')) as Data
- } else {
- let ok: boolean
- ;[ok, data] = await processTasks(octokit, username, {
- task,
- params,
- skipTask,
- })
- if (!ok) {
- return
- }
+ if (!ok) {
+ return
}
+ }
- let userBadges = getUserBadges()
- userBadges = presentBadges(
- allBadges.map((m) => m.default),
- data,
- userBadges,
- pickBadges,
- omitBadges,
- compact,
- )
+ let userBadges = repo.getUserBadges()
+ userBadges = presentBadges(
+ allBadges.map((m) => m.default),
+ data,
+ userBadges,
+ ctx.badgesPick,
+ ctx.badgesOmit,
+ ctx.badgesCompact,
+ )
- console.log(JSON.stringify(userBadges, null, 2))
+ console.log(JSON.stringify(userBadges, null, 2))
- if (owner && repo) {
- updateBadges(userBadges)
- updateReadme(userBadges, size)
- if (!dryrun && thereAreChanges()) {
- gitPush()
- }
+ if (repo.ready) {
+ updateBadges(userBadges, ctx.badgesDir, ctx.badgesDatafile)
+ updateReadme(userBadges, ctx.badgesSize, ctx.gitDir)
+ if (!ctx.dryrun && repo.hasChanges()) {
+ repo.push()
}
- } catch (e) {
- console.error(e)
- process.exit(1)
}
-})()
+}
+
+function isMain(metaurl = import.meta.url, scriptpath = process.argv[1]) {
+ if (metaurl.startsWith('file:')) {
+ const modulePath = url.fileURLToPath(metaurl).replace(/\.\w+$/, '')
+ const mainPath = fs.realpathSync(scriptpath).replace(/\.\w+$/, '')
+ return mainPath === modulePath
+ }
+
+ return false
+}
src/process-tasks.ts
@@ -1,28 +1,37 @@
import fs from 'node:fs'
-import { Octokit } from 'octokit'
import { GraphqlResponseError } from '@octokit/graphql'
import { Data } from './data.js'
import { TaskName } from './task.js'
import allTasks from './task/index.js'
+
+import { type Context } from './context.js'
import { createBatcher } from './batch.js'
const MAX_ATTEMPTS = 3
export async function processTasks(
- octokit: Octokit,
- username: string,
- {
- task,
- params,
- skipTask,
- }: { task?: string; params?: string; skipTask?: string } = {},
+ ctx: Pick<
+ Context,
+ | 'octokit'
+ | 'ghUser'
+ | 'dataDir'
+ | 'dataFile'
+ | 'dataTasks'
+ | 'taskName'
+ | 'taskSkip'
+ | 'taskParams'
+ >,
): Promise<[boolean, Data]> {
- if (!fs.existsSync('data')) {
- fs.mkdirSync('data')
- }
- const dataPath = `data/${username}.json`
- const tasksPath = `data/${username}.tasks.json`
- const skipTasks = new Set(skipTask?.split(',') || [])
+ const {
+ octokit,
+ ghUser: username,
+ dataFile,
+ dataTasks,
+ taskSkip,
+ taskName,
+ taskParams,
+ } = ctx
+ const taskSkipSet = new Set(taskSkip?.split(',') || [])
let data: Data = {
user: null!,
@@ -34,8 +43,8 @@ export async function processTasks(
discussionComments: [],
}
- if (fs.existsSync(dataPath)) {
- data = JSON.parse(fs.readFileSync(dataPath, 'utf8')) as Data
+ if (fs.existsSync(dataFile)) {
+ data = JSON.parse(fs.readFileSync(dataFile, 'utf8')) as Data
}
type Todo = {
@@ -53,16 +62,16 @@ export async function processTasks(
{ taskName: 'stars', params: { username }, attempts: 0 },
]
- if (task && params) {
+ if (taskName && taskParams) {
todo = [
{
- taskName: task as TaskName,
- params: Object.fromEntries(new URLSearchParams(params).entries()),
+ taskName: taskName as TaskName,
+ params: Object.fromEntries(new URLSearchParams(taskParams).entries()),
attempts: 0,
},
]
- } else if (fs.existsSync(tasksPath)) {
- const savedTodo = JSON.parse(fs.readFileSync(tasksPath, 'utf8')) as Todo[]
+ } else if (fs.existsSync(dataTasks)) {
+ const savedTodo = JSON.parse(fs.readFileSync(dataTasks, 'utf8')) as Todo[]
if (savedTodo.length > 0) {
todo = savedTodo
}
@@ -70,7 +79,7 @@ export async function processTasks(
while (todo.length > 0) {
const { taskName, params, attempts } = todo.shift()!
- if (skipTasks.has(taskName)) {
+ if (taskSkipSet.has(taskName)) {
console.log(`Skipping task ${taskName}`)
continue
}
@@ -120,8 +129,8 @@ export async function processTasks(
flush()
- fs.writeFileSync(dataPath, JSON.stringify(data, null, 2))
- fs.writeFileSync(tasksPath, JSON.stringify(todo, null, 2))
+ fs.writeFileSync(dataFile, JSON.stringify(data, null, 2))
+ fs.writeFileSync(dataTasks, JSON.stringify(todo, null, 2))
}
return [true, data]
src/repo.ts
@@ -1,56 +1,60 @@
import fs from 'node:fs'
-import { chdir } from 'node:process'
+import path from 'node:path'
import { Badge } from './badges.js'
-import { exec, execWithOutput } from './utils.js'
-
-export function syncRepo(owner: string, repo: string, token: string) {
- if (fs.existsSync('repo')) {
- chdir('repo')
- exec('git', ['pull'])
- chdir('..')
- return
- }
-
- exec('git', [
- 'clone',
- '--depth=1',
- `https://${owner}:${token}@github.com/${owner}/${repo}.git`,
- 'repo',
- ])
-
- chdir('repo')
-
- exec('git', ['config', 'user.name', 'My Badges'])
- exec('git', ['config', 'user.email', 'my-badges@users.noreply.github.com'])
-
- chdir('..')
-}
-
-export function thereAreChanges(): boolean {
- chdir('repo')
-
- const changes = execWithOutput('git', ['status', '--porcelain']).trim()
-
- chdir('..')
-
- return changes !== ''
-}
-
-export function gitPush() {
- chdir('repo')
-
- exec('git', ['add', '.'])
- exec('git', ['status'])
- exec('git', ['commit', '-m', 'Update badges'])
- exec('git', ['push'])
-
- chdir('..')
-}
-
-export function getUserBadges(): Badge[] {
- if (!fs.existsSync('repo/my-badges/my-badges.json')) {
- return []
+import { $ as _$ } from './utils.js'
+import { Context } from './context.js'
+
+export function getRepo({
+ gitDir,
+ ghToken,
+ ghRepoOwner,
+ ghRepoName,
+ gitName,
+ gitEmail,
+ badgesDatafile,
+}: Context) {
+ let ready = false
+
+ const cwd = gitDir
+ const dryrun = !ghRepoOwner || !ghRepoName
+ const basicAuth = ghToken ? `${ghRepoOwner}:${ghToken}@` : ''
+ const gitUrl = `https://${basicAuth}github.com/${ghRepoOwner}/${ghRepoName}.git`
+ const $ = _$({
+ cwd,
+ sync: true,
+ })
+ return {
+ get ready() {
+ return ready
+ },
+ pull() {
+ if (dryrun) return
+ if (fs.existsSync(path.resolve(cwd, '.git'))) {
+ $`git pull`
+ return
+ }
+
+ $`git clone --depth=1 ${gitUrl} .`
+ $`git config user.name ${gitName}`
+ $`git config user.email ${gitEmail}`
+ ready = true
+ },
+ push() {
+ if (!ready) return
+ $`git add .`
+ $`git status`
+ $`git commit -m 'Update badges'`
+ $`git push`
+ },
+ hasChanges(): boolean {
+ if (!ready) return false
+ return $`git status --porcelain`.stdout.trim() !== ''
+ },
+ getUserBadges(): Badge[] {
+ if (!fs.existsSync(badgesDatafile)) return []
+
+ const data = fs.readFileSync(badgesDatafile, 'utf8')
+ return JSON.parse(data)
+ },
}
- const data = fs.readFileSync('repo/my-badges/my-badges.json', 'utf8')
- return JSON.parse(data)
}
src/update-badges.ts
@@ -1,17 +1,18 @@
import fs from 'node:fs'
-import { chdir } from 'node:process'
+import path from 'node:path'
import { Badge } from './badges.js'
import { quoteAttr } from './utils.js'
-export function updateBadges(badges: Badge[]) {
- chdir('repo')
-
- fs.mkdirSync('my-badges', { recursive: true })
- fs.writeFileSync('my-badges/my-badges.json', JSON.stringify(badges, null, 2))
+export function updateBadges(
+ badges: Badge[],
+ badgesDir: string,
+ badgesDatafile: string,
+) {
+ fs.mkdirSync(badgesDir, { recursive: true })
+ fs.writeFileSync(badgesDatafile, JSON.stringify(badges, null, 2))
for (const badge of badges) {
- const badgePath = `my-badges/${badge.id}.md`
-
+ const badgePath = path.resolve(badgesDir, `${badge.id}.md`)
const desc = quoteAttr(badge.desc)
const content =
`<img src="${badge.image}" alt="${desc}" title="${desc}" width="128">\n` +
@@ -23,6 +24,4 @@ export function updateBadges(badges: Badge[]) {
fs.writeFileSync(badgePath, content)
}
-
- chdir('..')
}
src/update-readme.ts
@@ -1,24 +1,27 @@
import fs from 'node:fs'
-import { chdir } from 'node:process'
+import path from 'node:path'
import { Badge } from './badges.js'
import { quoteAttr } from './utils.js'
-export function updateReadme(badges: Badge[], size: number | string) {
- chdir('repo')
-
- const readmeFilename = detectReadmeFilename()
+export function updateReadme(
+ badges: Badge[],
+ size: number | string,
+ repoDir: string,
+) {
+ const readmeFilename = detectReadmeFilename(repoDir)
const readmeContent = fs.readFileSync(readmeFilename, 'utf8')
const content = generateReadme(readmeContent, badges, size)
fs.writeFileSync(readmeFilename, content)
-
- chdir('..')
}
-function detectReadmeFilename(): string {
- if (fs.existsSync('README.md')) return 'README.md'
- if (fs.existsSync('readme.md')) return 'readme.md'
- throw new Error('Cannot find README.md')
+function detectReadmeFilename(cwd: string): string {
+ const file = ['README.md', 'readme.md']
+ .map((f) => path.resolve(cwd, f))
+ .find((f) => fs.existsSync(f))
+ if (!file) throw new Error('Cannot find README.md')
+
+ return file
}
export function generateReadme(
src/utils.ts
@@ -5,6 +5,8 @@ import { Commit } from './task/commits/commits.graphql.js'
import { PullRequest } from './task/pulls/pulls.graphql.js'
import { Issue } from './task/issues/issues.graphql.js'
+export { $, type TShellSync } from 'zurk'
+
export function query<T extends Query>(
octokit: Octokit,
query: T,
test/main.test.ts
@@ -0,0 +1,16 @@
+import { describe, it, expect } from 'vitest'
+import { main } from '../src/main.js'
+import os from 'node:os'
+
+const temp = `${os.tmpdir()}/${Math.random().toString(36).slice(2)}`
+
+describe.skip('main', () => {
+ console.log('temp', temp)
+ it(
+ 'generates badges by repo name',
+ async () => {
+ await main(['--user', 'semrel-extra-bot', '--cwd', temp])
+ },
+ 15 * 60 * 1000,
+ )
+})
src/present-badges.test.ts → test/present-badges.test.ts
@@ -1,7 +1,7 @@
import { describe, test, expect } from 'vitest'
-import { presentBadges } from './present-badges.js'
-import { Badge, define } from './badges.js'
-import { Data } from './data.js'
+import { presentBadges } from '../src/present-badges.js'
+import { Badge, define } from '../src/badges.js'
+import { Data } from '../src/data.js'
describe('present-badges', () => {
const data: Data = {
@@ -38,7 +38,7 @@ describe('present-badges', () => {
test('presentBadges() applies `pick`', async () => {
const userBadges = presentBadges(
- [await import('#badges/stars/stars.js')].map((m) => m.default),
+ [await import('../badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-100', 'stars-500'],
@@ -76,7 +76,7 @@ describe('present-badges', () => {
test('presentBadges() applies `omit`', async () => {
const userBadges = presentBadges(
- [await import('#badges/stars/stars.js')].map((m) => m.default),
+ [await import('../badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-100', 'stars-500'],
@@ -102,7 +102,7 @@ describe('present-badges', () => {
test('presentBadges() supports masks for `omit` && `pick`', async () => {
const userBadges = presentBadges(
- [await import('#badges/stars/stars.js')].map((m) => m.default),
+ [await import('../badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-*'],
@@ -140,7 +140,7 @@ describe('present-badges', () => {
test('presentBadges() applies `compact`', async () => {
const userBadges = presentBadges(
- [await import('#badges/stars/stars.js')].map((m) => m.default),
+ [await import('../badges/stars/stars.js')].map((m) => m.default),
data,
[],
['stars-1000', 'stars-2000', 'stars-5000'],
test/repo.test.ts
@@ -0,0 +1,25 @@
+import path from 'node:path'
+import fs from 'node:fs'
+import os from 'node:os'
+import { describe, it, expect, afterAll } from 'vitest'
+import { getRepo } from '../src/repo.js'
+import { createCtx } from '../src/context.js'
+
+const temp = `${os.tmpdir()}/${Math.random().toString(36).slice(2)}`
+
+describe('repo API', () => {
+ const ctx = createCtx(['--repo', 'webpod/zurk', '--cwd', temp])
+ const repo = getRepo(ctx)
+
+ describe('syncRepo()', () => {
+ it('should sync the repo', () => {
+ repo.pull()
+ const pkgJson = JSON.parse(
+ fs.readFileSync(path.resolve(temp, 'repo/package.json'), 'utf-8'),
+ )
+ expect(pkgJson.name).toEqual('zurk')
+ })
+ })
+})
+
+afterAll(() => fs.rmdirSync(temp, { recursive: true }))
src/update-readme.test.ts → test/update-readme.test.ts
@@ -1,8 +1,8 @@
import { describe, test, expect } from 'vitest'
-import { generateReadme } from './update-readme.js'
-import type { Badge } from './badges.js'
-import abcPresenter from '#badges/abc-commit/abc-commit.js'
-import { badgeCollection } from './present-badges.js'
+import { generateReadme } from '../src/update-readme.js'
+import type { Badge } from '../src/badges.js'
+import abcPresenter from '../badges/abc-commit/abc-commit.js'
+import { badgeCollection } from '../src/present-badges.js'
describe('generateReadme()', () => {
test('injects badges to md contents', () => {
package-lock.json
@@ -14,7 +14,8 @@
"@octokit/plugin-throttling": "^9.3.2",
"megaera": "^1.0.2",
"minimist": "^1.2.8",
- "octokit": "^4.0.2"
+ "octokit": "^4.0.2",
+ "zurk": "^0.6.3"
},
"bin": {
"update-my-badges": "dist/src/main.js"
@@ -1533,12 +1534,13 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -1702,9 +1704,9 @@
"dev": true
},
"node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1880,10 +1882,11 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -2085,6 +2088,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -2235,12 +2239,13 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -2808,6 +2813,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -3182,6 +3188,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zurk": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/zurk/-/zurk-0.6.3.tgz",
+ "integrity": "sha512-1EyIiD9td75xMmmZv9kD1YXOtG2vPxXZFqXWdgFd2Fu55OLWLgfmvFqaQKOKotpbXeQ6JpsAsaPmU4By9GEnoA==",
+ "license": "MIT"
+ },
"node_modules/zx": {
"version": "8.2.4",
"resolved": "https://registry.npmjs.org/zx/-/zx-8.2.4.tgz",
package.json
@@ -28,7 +28,8 @@
"@octokit/plugin-throttling": "^9.3.2",
"megaera": "^1.0.2",
"minimist": "^1.2.8",
- "octokit": "^4.0.2"
+ "octokit": "^4.0.2",
+ "zurk": "^0.6.3"
},
"devDependencies": {
"@octokit/graphql-schema": "^15.25.0",