-
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.
- Loading branch information
Showing
10 changed files
with
3,674 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,30 @@ | ||
name: Deploy | ||
|
||
on: | ||
# Run this workflow whenever a new commit is pushed to main. | ||
push: { branches: [master] } | ||
# Run this workflow once per day, at 10:15 UTC | ||
schedule: [{ cron: "00 00 * * *" }] | ||
# Run this workflow when triggered manually in GitHub’s UI. | ||
workflow_dispatch: {} | ||
|
||
jobs: | ||
deploy: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: 20 | ||
cache: npm | ||
- run: npm install | ||
- name: Build | ||
run: npm run build | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
- name: Deploy to Observable Cloud | ||
# This parameter to `--message` will use the latest commit message | ||
run: npm run deploy -- --message "$(git log -1 --pretty=%s)" | ||
env: | ||
# Authentication information. See below for how to set this up. | ||
OBSERVABLE_TOKEN: ${{ secrets.OBSERVABLE_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,26 @@ | ||
name: Preview | ||
|
||
on: | ||
pull_request: { branches: [master] } | ||
# Run this workflow when triggered manually in GitHub’s UI. | ||
workflow_dispatch: {} | ||
|
||
jobs: | ||
deploy: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: 20 | ||
cache: npm | ||
- run: npm install | ||
- name: Build | ||
run: npm run build | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
- name: Deploy to GitHub Pages | ||
uses: peaceiris/actions-gh-pages@v3 | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
publish_dir: ./dist |
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 @@ | ||
.DS_Store | ||
dist/ | ||
docs/.observablehq/cache/ | ||
node_modules/ | ||
yarn-error.log |
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 @@ | ||
{ | ||
"projectId": "3a0ad35943a5d91c", | ||
"projectSlug": "oscp", | ||
"workspaceLogin": "antv" | ||
} |
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,42 @@ | ||
import { Chart } from "npm:@antv/g2"; | ||
import * as d3 from "npm:d3-array"; | ||
|
||
let chart; | ||
|
||
export function bar(data, { width } = {}) { | ||
if (chart) chart.destroy(); | ||
|
||
const groups = d3.groups(data, (d) => d.userName); | ||
|
||
chart = new Chart({ | ||
width, | ||
height: groups.length * 20 + 100, | ||
marginRight: 30, | ||
}); | ||
|
||
chart.options({ | ||
type: "interval", | ||
title: "贡献者排行", | ||
coordinate: { transform: [{ type: "transpose" }] }, | ||
data, | ||
encode: { | ||
x: "userName", | ||
}, | ||
transform: [ | ||
{ type: "groupX", y: "count" }, | ||
{ type: "sortX", by: "y", reverse: true }, | ||
], | ||
scale: { | ||
x: { padding: 0.2 }, | ||
y: { nice: true }, | ||
}, | ||
axis: { | ||
x: { title: "Github 昵称" }, | ||
y: { title: "PR 数量" }, | ||
}, | ||
}); | ||
|
||
chart.render(); | ||
|
||
return chart.getContainer(); | ||
} |
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,81 @@ | ||
import { csvFormat } from "d3-dsv"; | ||
import { Octokit } from "octokit"; | ||
|
||
async function pr( | ||
octokit, | ||
{ startDate = null, repo = "G2", per_page = 100 } = {} | ||
) { | ||
let page = 1; | ||
const PRs = []; | ||
do { | ||
const { data } = await octokit.request(`GET /repos/antvis/${repo}/pulls`, { | ||
state: "all", | ||
sort: "created", | ||
direction: "desc", | ||
page, | ||
per_page, | ||
headers: { | ||
"X-GitHub-Api-Version": "2022-11-28", | ||
}, | ||
}); | ||
if (!data.length) return PRs; | ||
const index = data.findIndex((d, i) => { | ||
const next = data[i + 1]; | ||
if (!next) return false; | ||
const now = new Date(d.created_at); | ||
const yes = new Date(next.created_at); | ||
const start = new Date(startDate); | ||
return now > start && start > yes; | ||
}); | ||
const sliced = index === -1 ? data : data.slice(0, index + 1); | ||
PRs.push(...sliced); | ||
if (index !== -1) return PRs; | ||
page++; | ||
} while (startDate && page < 100); | ||
return PRs; | ||
} | ||
|
||
function oneYearAgo(date) { | ||
const year = date.getFullYear() - 1; | ||
date.setFullYear(year); | ||
return date.toISOString(); | ||
} | ||
|
||
const octokit = new Octokit({ | ||
auth: process.env.GITHUB_TOKEN, | ||
}); | ||
|
||
const startDate = oneYearAgo(new Date()); | ||
|
||
const PRs = [ | ||
...(await pr(octokit, { startDate, repo: "G2" })).map((d) => ({ | ||
...d, | ||
repo: "G2", | ||
})), | ||
...(await pr(octokit, { startDate, repo: "G6" })).map((d) => ({ | ||
...d, | ||
repo: "G6", | ||
})), | ||
...(await pr(octokit, { startDate, repo: "L7" })).map((d) => ({ | ||
...d, | ||
repo: "L7", | ||
})), | ||
]; | ||
|
||
const ADMIN_ROLES = new Set(["MEMBER", "OWNER"]); | ||
|
||
const data = PRs.map((d) => ({ | ||
contributor: ADMIN_ROLES.has(d.author_association) ? 0 : 1, | ||
// author_association: d.author_association, | ||
repo: d.repo, | ||
userName: d.user.login, | ||
// userAvatar: d.user.avatar_url, | ||
mergeAt: d.merged_at, | ||
// url: d.html_url, | ||
// TODO: add more fields | ||
})) | ||
.filter((d) => d.userName !== "github-actions[bot]") | ||
.filter((d) => d.userName !== "dependabot-preview[bot]") | ||
.filter((d) => d.userName !== "dependabot[bot]"); | ||
|
||
process.stdout.write(csvFormat(data)); |
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,83 @@ | ||
--- | ||
toc: false | ||
--- | ||
|
||
```js | ||
import { bar } from "./components/bar.js"; | ||
const pr = FileAttachment("data/pr.csv").csv({ typed: true }); | ||
``` | ||
|
||
```js | ||
function monthAgo(number = 1) { | ||
return (date) => { | ||
const month = date.getMonth() - number; | ||
date.setMonth(month); | ||
return date.toISOString(); | ||
}; | ||
} | ||
|
||
const map = new Map([ | ||
["1个月", monthAgo(1)], | ||
["3个月", monthAgo(3)], | ||
["半年", monthAgo(6)], | ||
["1年", monthAgo(12)], | ||
]); | ||
|
||
const startDate = map.get(ago)(new Date()); | ||
|
||
const isContributor = (d) => d.contributor === 1; | ||
|
||
const selected = pr | ||
.filter((d) => (repo === "全部" ? true : d.repo === repo)) | ||
.filter((d) => new Date(d.mergeAt) > new Date(startDate)); | ||
|
||
const contributors = Array.from( | ||
new Set(selected.filter(isContributor).map((d) => d.userName)) | ||
).length; | ||
|
||
const PRs = selected.filter(isContributor).length; | ||
const allPRs = selected.length; | ||
const ratio = ((PRs / allPRs) * 100).toFixed(0); | ||
``` | ||
|
||
<h1>AntV OSCP</h1> | ||
|
||
```js | ||
const ago = view( | ||
Inputs.radio(["1个月", "3个月", "半年", "1年"], { | ||
label: "时间范围", | ||
value: "1年", | ||
}) | ||
); | ||
``` | ||
|
||
```js | ||
const repo = view( | ||
Inputs.radio(["全部", "G2", "G6", "L7"], { label: "技术栈", value: "全部" }) | ||
); | ||
``` | ||
|
||
<div class="grid grid-cols-4"> | ||
<span class="card"> | ||
<h2>社区贡献者</h2> | ||
<span class="big">${contributors}</span> | ||
</span> | ||
<span class="card"> | ||
<h2>社区贡献者 PR</h2> | ||
<span class="big">${PRs}</span> | ||
</span> | ||
<span class="card"> | ||
<h2>所有 PR</h2> | ||
<span class="big">${selected.length}</span> | ||
</span> | ||
<span class="card"> | ||
<h2>社区贡献率</h2> | ||
<span class="big">${ratio + `%`}</span> | ||
</span> | ||
</div> | ||
|
||
<div class="grid grid-cols-1"> | ||
<div class="card" style="padding:0"> | ||
${resize((width) => bar(selected, {width}))} | ||
</div> | ||
</div> |
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,28 @@ | ||
// See https://observablehq.com/framework/config for documentation. | ||
export default { | ||
// The project’s title; used in the sidebar and webpage titles. | ||
title: "AntV OSCP", | ||
|
||
// The pages and sections in the sidebar. If you don’t specify this option, | ||
// all pages will be listed in alphabetical order. Listing pages explicitly | ||
// lets you organize them into sections and have unlisted pages. | ||
// pages: [ | ||
// { | ||
// name: "Examples", | ||
// pages: [ | ||
// {name: "Dashboard", path: "/example-dashboard"}, | ||
// {name: "Report", path: "/example-report"} | ||
// ] | ||
// } | ||
// ], | ||
|
||
// Some additional configuration options and their defaults: | ||
// theme: "default", // try "light", "dark", "slate", etc. | ||
// header: "", // what to show in the header (HTML) | ||
// footer: "Built with Observable.", // what to show in the footer (HTML) | ||
// toc: true, // whether to show the table of contents | ||
// pager: true, // whether to show previous & next links in the footer | ||
// root: "docs", // path to the source root for preview | ||
// output: "dist", // path to the output root for build | ||
// search: true, // activate search | ||
}; |
Oops, something went wrong.