mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-28 11:25:00 +00:00
* chore: add GitHub-reward form, scripts & actions * fix: Deno system permissions in GitHub actions * fix: 3 detail bugs
125 lines
3.2 KiB
TypeScript
125 lines
3.2 KiB
TypeScript
import "npm:array-unique-proposal";
|
|
|
|
import { components } from "npm:@octokit/openapi-types";
|
|
import { $, argv, YAML } from "npm:zx";
|
|
|
|
import { Reward } from "./type.ts";
|
|
|
|
$.verbose = true;
|
|
|
|
const [
|
|
repositoryOwner,
|
|
repositoryName,
|
|
issueNumber,
|
|
payer, // GitHub username of the payer (provided by workflow, defaults to issue creator)
|
|
currency,
|
|
reward,
|
|
] = argv._;
|
|
|
|
interface PRMeta {
|
|
author: components["schemas"]["simple-user"];
|
|
assignees: components["schemas"]["simple-user"][];
|
|
}
|
|
|
|
const graphqlQuery = `
|
|
query($owner: String!, $name: String!, $number: Int!) {
|
|
repository(owner: $owner, name: $name) {
|
|
issue(number: $number) {
|
|
closedByPullRequestsReferences(first: 10) {
|
|
nodes {
|
|
url
|
|
merged
|
|
mergeCommit {
|
|
oid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
const PR_DATA = await $`gh api graphql \
|
|
-f query=${graphqlQuery} \
|
|
-f owner=${repositoryOwner} \
|
|
-f name=${repositoryName} \
|
|
-F number=${issueNumber} \
|
|
--jq '.data.repository.issue.closedByPullRequestsReferences.nodes[] | select(.merged == true) | {url: .url, mergeCommitSha: .mergeCommit.oid}' | head -n 1`;
|
|
|
|
const prData = PR_DATA.text().trim();
|
|
|
|
if (!prData)
|
|
throw new ReferenceError("No merged PR is found for the given issue number.");
|
|
|
|
const { url: PR_URL, mergeCommitSha } = JSON.parse(prData);
|
|
|
|
if (!PR_URL || !mergeCommitSha)
|
|
throw new Error("Missing required fields in PR data");
|
|
|
|
console.table({ PR_URL, mergeCommitSha });
|
|
|
|
const { author, assignees }: PRMeta = await (
|
|
await $`gh pr view ${PR_URL} --json author,assignees`
|
|
).json();
|
|
|
|
function isBotUser(login: string) {
|
|
const lowerLogin = login.toLowerCase();
|
|
return (
|
|
lowerLogin.includes("copilot") ||
|
|
lowerLogin.includes("[bot]") ||
|
|
lowerLogin === "github-actions[bot]" ||
|
|
lowerLogin.endsWith("[bot]")
|
|
);
|
|
}
|
|
|
|
// Filter out Bot users from the list
|
|
const allUsers = [
|
|
author.login,
|
|
...assignees.map(({ login }) => login),
|
|
].uniqueBy();
|
|
|
|
const users = allUsers.filter((login) => !isBotUser(login));
|
|
|
|
console.log(`All users: ${allUsers.join(", ")}`);
|
|
console.log(`Filtered users (excluding bots): ${users.join(", ")}`);
|
|
|
|
if (!users[0])
|
|
throw new ReferenceError(
|
|
"No real users found (all users are bots). Skipping reward distribution.",
|
|
);
|
|
|
|
const rewardNumber = parseFloat(reward);
|
|
|
|
if (isNaN(rewardNumber) || rewardNumber <= 0)
|
|
throw new RangeError(
|
|
`Reward amount is not a valid number, can not proceed with reward distribution. Received reward value: ${reward}`,
|
|
);
|
|
|
|
const averageReward = (rewardNumber / users.length).toFixed(2);
|
|
|
|
const list: Reward[] = users.map((login) => ({
|
|
issue: `#${issueNumber}`,
|
|
payer: `@${payer}`,
|
|
payee: `@${login}`,
|
|
currency,
|
|
reward: parseFloat(averageReward),
|
|
}));
|
|
const listText = YAML.stringify(list);
|
|
|
|
console.log(listText);
|
|
|
|
await $`git config user.name "github-actions[bot]"`;
|
|
await $`git config user.email "github-actions[bot]@users.noreply.github.com"`;
|
|
|
|
await $`git tag -a "reward-${issueNumber}" ${mergeCommitSha} -m ${listText}`;
|
|
await $`git push origin --tags --no-verify`;
|
|
|
|
await $`git config unset user.name`;
|
|
await $`git config unset user.email`;
|
|
|
|
const commentBody = `## Reward data
|
|
|
|
\`\`\`yml
|
|
${listText}
|
|
\`\`\`
|
|
`;
|
|
await $`gh issue comment ${issueNumber} --body ${commentBody}`;
|