forked from Magickbase/websites
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement scripts report:update and report:discussion
- Loading branch information
1 parent
6cda32c
commit b25108c
Showing
14 changed files
with
739 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
name: Update Report Snapshot | ||
|
||
on: | ||
workflow_dispatch: | ||
schedule: | ||
- cron: '0 0 * * 1' | ||
|
||
jobs: | ||
default: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
# peter-evans/create-pull-request requires the following permissions: | ||
pull-requests: write | ||
contents: write | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
ref: ${{ github.ref }} | ||
|
||
- name: report:update | ||
id: report_update | ||
env: | ||
# The script requires public_repo, read:org, read:project permissions, and needs a personal access token (classic) to obtain these permissions. | ||
GITHUB_TOKEN: ${{ secrets.REPORT_GITHUB_TOKEN }} | ||
run: | | ||
yarn install | ||
{ | ||
echo 'DEVLOG<<EOF' | ||
yarn workspace @magickbase-website/scripts report:update | sed '0,/^generateDevlogFromSnapshotsDiff():$/d' | ||
echo EOF | ||
} >> $GITHUB_OUTPUT | ||
git add packages/scripts/snapshots | ||
- name: Set GPG | ||
uses: crazy-max/ghaction-import-gpg@v5 | ||
with: | ||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} | ||
passphrase: ${{ secrets.GPG_PASSPHRASE }} | ||
git_user_signingkey: true | ||
git_commit_gpgsign: true | ||
|
||
- name: Open PR to repo | ||
uses: peter-evans/create-pull-request@v5 | ||
with: | ||
title: Update Report Snapshot | ||
commit-message: 'feat: update report snapshot' | ||
body: ' | ||
After this PR is merged, a corresponding devlog discussion will be automatically created, with the content preview as follows | ||
--- | ||
${{ steps.report_update.outputs.DEVLOG }} | ||
' | ||
committer: ${{ vars.COMMITTER }} | ||
branch: update-report-snapshot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# For accessing api.github.com | ||
# https://docs.github.com/en/rest/overview/authenticating-to-the-rest-api?apiVersion=2022-11-28 | ||
GITHUB_TOKEN= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** @type {import("eslint").Linter.Config} */ | ||
const config = { | ||
root: true, | ||
extends: ['@magickbase-website/eslint-config/next.js'], | ||
} | ||
|
||
module.exports = config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const path = require('path') | ||
|
||
module.exports = { | ||
'*.{js,cjs,mjs,jsx,ts,tsx}': ['prettier --write', 'eslint --fix'], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"name": "@magickbase-website/scripts", | ||
"version": "0.1.0", | ||
"private": true, | ||
"type": "module", | ||
"scripts": { | ||
"report:update": "node --loader ts-node/esm src/update_report_snapshot.ts", | ||
"report:discussion": "node --loader ts-node/esm src/create_report_discussion.ts" | ||
}, | ||
"dependencies": { | ||
"@octokit/plugin-paginate-graphql": "^4.0.0", | ||
"@octokit/plugin-paginate-rest": "^6.1.2", | ||
"@octokit/rest": "^19.0.11" | ||
}, | ||
"devDependencies": { | ||
"@magickbase-website/config": "workspace:^", | ||
"@magickbase-website/eslint-config": "workspace:^", | ||
"@types/eslint": "^8.56.0", | ||
"@types/node": "^20.2.5", | ||
"eslint": "^8.56.0", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.1.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import './prepare' | ||
import { createDevlogDiscussion } from './utils/report' | ||
|
||
await createDevlogDiscussion() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import pkg from '@next/env' | ||
|
||
const { loadEnvConfig } = pkg | ||
loadEnvConfig(process.cwd(), true) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import './prepare' | ||
import { generateDevlogFromSnapshotsDiff, updateSnapshots } from './utils/report' | ||
|
||
await updateSnapshots() | ||
// These outputs are for use with GitHub Actions. | ||
console.log('generateDevlogFromSnapshotsDiff():') | ||
console.log(generateDevlogFromSnapshotsDiff()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export function assert(assertion: unknown, msg = 'assertion failed'): asserts assertion { | ||
if (!assertion) { | ||
throw new Error(msg) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { existsSync, mkdirSync } from 'fs' | ||
import { dirname } from 'path' | ||
|
||
export function ensureFileFolderExists(filePath: string) { | ||
const folder = dirname(filePath) | ||
if (existsSync(folder)) return | ||
mkdirSync(folder, { recursive: true }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
import { Octokit } from '@octokit/rest' | ||
import { paginateRest } from '@octokit/plugin-paginate-rest' | ||
import { paginateGraphql } from '@octokit/plugin-paginate-graphql' | ||
import { assert } from './error' | ||
|
||
const TOKEN = process.env.GITHUB_TOKEN | ||
assert(TOKEN != null && TOKEN !== '', 'GITHUB_TOKEN is required') | ||
|
||
const EnhancedOctokit = Octokit.plugin(paginateRest, paginateGraphql) | ||
const octokit = new EnhancedOctokit({ auth: TOKEN }) | ||
|
||
const GQL_ProjectV2FieldCommon_FIELDS = () => ` | ||
... on ProjectV2FieldCommon { | ||
name | ||
} | ||
` | ||
const GQL_PROJECTV2ITEMFIELDVALUE_FIELDS = () => ` | ||
... on ProjectV2ItemFieldTextValue { | ||
text | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldNumberValue { | ||
number | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldDateValue { | ||
date | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldSingleSelectValue { | ||
name | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldIterationValue { | ||
title | ||
startDate | ||
duration | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldLabelValue { | ||
labels (first: 100) { | ||
nodes { | ||
id | ||
name | ||
description | ||
} | ||
} | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldMilestoneValue { | ||
milestone { | ||
title | ||
dueOn | ||
} | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldPullRequestValue { | ||
pullRequests(first: 100) { | ||
nodes { | ||
title | ||
url | ||
} | ||
} | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldRepositoryValue { | ||
repository { | ||
name | ||
url | ||
} | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldReviewerValue { | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
... on ProjectV2ItemFieldUserValue { | ||
field {${GQL_ProjectV2FieldCommon_FIELDS()}} | ||
} | ||
` | ||
|
||
export async function getOrganizationProjects(org: string) { | ||
const res = await octokit.graphql<{ | ||
organization: { | ||
projectsV2: { | ||
nodes: { | ||
id: string | ||
number: number | ||
title: string | ||
}[] | ||
} | ||
} | ||
}>( | ||
` | ||
query($login: String!) { | ||
organization(login: $login) { | ||
projectsV2(first: 100, query: "is:open") { | ||
totalCount | ||
nodes { | ||
id | ||
number | ||
title | ||
} | ||
} | ||
} | ||
} | ||
`, | ||
{ | ||
login: org, | ||
}, | ||
) | ||
|
||
return res.organization.projectsV2.nodes | ||
} | ||
|
||
export interface ProjectItem { | ||
id: string | ||
content: { title: string; number?: number; url?: string } | ||
fieldValues: { | ||
nodes: { | ||
text?: string | ||
number?: number | ||
date?: unknown | ||
name?: string | ||
title?: string | ||
startDate?: unknown | ||
duration?: unknown | ||
labels?: { nodes: { name: string }[] } | ||
milestone?: { title: string; dueOn: unknown } | ||
pullRequests?: { nodes: { title: string; url: string }[] } | ||
repository?: { name: string; url: string } | ||
field: { name: string } | ||
}[] | ||
} | ||
} | ||
|
||
export async function getProjectItems(id: string) { | ||
const res = await octokit.graphql.paginate<{ | ||
node: { | ||
items: { | ||
nodes: ProjectItem[] | ||
} | ||
} | ||
}>( | ||
` | ||
query($cursor: String, $id: ID!) { | ||
node(id: $id) { | ||
... on ProjectV2 { | ||
items(first: 20, after: $cursor) { | ||
nodes { | ||
id | ||
content { | ||
... on DraftIssue { | ||
title | ||
} | ||
... on Issue { | ||
title | ||
number | ||
url | ||
} | ||
... on PullRequest { | ||
title | ||
number | ||
url | ||
} | ||
} | ||
fieldValues(first: 100) { | ||
nodes { | ||
${GQL_PROJECTV2ITEMFIELDVALUE_FIELDS()} | ||
} | ||
} | ||
} | ||
pageInfo { | ||
hasNextPage | ||
endCursor | ||
} | ||
} | ||
} | ||
} | ||
} | ||
`, | ||
{ | ||
id, | ||
}, | ||
) | ||
|
||
return res.node.items.nodes | ||
} | ||
|
||
export async function createDiscussion( | ||
repoOwner: string, | ||
repoName: string, | ||
category: string, | ||
title: string, | ||
body: string, | ||
) { | ||
const repoRes = await octokit.graphql<{ | ||
repository: { | ||
id: string | ||
discussionCategories: { | ||
nodes: { | ||
id: string | ||
name: string | ||
}[] | ||
} | ||
} | ||
}>( | ||
` | ||
query($owner: String!, $name: String!) { | ||
repository(owner: $owner, name: $name) { | ||
id | ||
discussionCategories(first: 100) { | ||
nodes { | ||
id | ||
name | ||
} | ||
} | ||
} | ||
} | ||
`, | ||
{ | ||
owner: repoOwner, | ||
name: repoName, | ||
}, | ||
) | ||
|
||
const categoryId = repoRes.repository.discussionCategories.nodes.find(n => n.name === category)?.id | ||
assert(categoryId) | ||
|
||
const createRes = octokit.graphql<{ | ||
createDiscussion: { | ||
discussion: { | ||
id: string | ||
} | ||
} | ||
}>( | ||
` | ||
mutation($repoId: ID!, $categoryId: ID!, $title: String!, $body: String!) { | ||
createDiscussion(input: {repositoryId: $repoId, categoryId: $categoryId, body: $body, title: $title}) { | ||
discussion { | ||
id | ||
} | ||
} | ||
} | ||
`, | ||
{ | ||
repoId: repoRes.repository.id, | ||
categoryId, | ||
title, | ||
body, | ||
}, | ||
) | ||
|
||
return (await createRes).createDiscussion.discussion | ||
} |
Oops, something went wrong.