Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement handling RFCs #1212

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3cae67f
Update github.ts
xno-miner Jun 17, 2024
60498ef
Update index.ts
xno-miner Jun 17, 2024
c22b1c8
Minor fix
xno-miner Jun 17, 2024
f0e9c3d
Update helpers/github.ts
xno-miner Jun 17, 2024
9258750
Update devpool-issue-handler.test.ts
xno-miner Jun 17, 2024
a6c3c1e
Update devpool-issue-handler.test.ts
xno-miner Jun 17, 2024
d96e69e
Update index.ts
xno-miner Jun 17, 2024
22ebb9c
Update github.ts
xno-miner Jun 17, 2024
fe8c4c6
Minor fix
xno-miner Jun 17, 2024
80ce59b
Minor clean
xno-miner Jun 17, 2024
20d74be
Fix getting repo name
xno-miner Jun 17, 2024
b77c0c0
Moved DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME, DEVPOOL_RFC_OWNER_NAME a…
xno-miner Jun 28, 2024
4f3c962
Moved the DEVPOOL_ variables to .env (copy the values from .env.example)
xno-miner Jun 28, 2024
128c5d8
don't tweet rfcs
xno-miner Jun 28, 2024
212502f
don't tweet rfcs
xno-miner Jun 28, 2024
ea31d8a
Moved the DEVPOOL_ variables back from env
xno-miner Jun 29, 2024
a08862c
Improved code readability
xno-miner Jun 29, 2024
4cafbe3
Minor fix
xno-miner Jun 29, 2024
179586e
Further improved readability
xno-miner Jun 29, 2024
5263f17
Minor fix
xno-miner Jun 29, 2024
1a65d43
Create env variables for devpool/RFC
xno-miner Jul 2, 2024
133d263
Merge branch 'development' into development
xno-miner Jul 25, 2024
66f7d63
Create tests for RFCs
xno-miner Jul 26, 2024
7a583ab
Add missing files
xno-miner Jul 26, 2024
ed3bbf0
JSON.parse RFC env
xno-miner Jul 29, 2024
ea374eb
quotes in ymls
xno-miner Aug 1, 2024
5a7f812
Fix env and enable rfc test
xno-miner Aug 1, 2024
6318d84
minor cleanup
xno-miner Aug 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ TWITTER_API_KEY=
TWITTER_API_KEY_SECRET=
TWITTER_ACCESS_TOKEN=
TWITTER_ACCESS_TOKEN_SECRET=

DEVPOOL_OWNER_NAME=ubiquity
DEVPOOL_REPO_NAME=devpool-directory
RFC=false
3 changes: 3 additions & 0 deletions .github/workflows/jest-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ env:
TWITTER_API_KEY_SECRET: "<twitter_api_secret>"
TWITTER_ACCESS_TOKEN: "<twitter_access_token>"
TWITTER_ACCESS_TOKEN_SECRET: "<twitter_access_token_secret>"
DEVPOOL_OWNER_NAME: "ubiquity"
DEVPOOL_REPO_NAME: "devpool-directory"
RFC: "false"

jobs:
testing:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/sync-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ jobs:
TWITTER_API_KEY_SECRET: ${{ secrets.TWITTER_API_KEY_SECRET }}
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
DEVPOOL_OWNER_NAME: "ubiquity"
DEVPOOL_REPO_NAME: "devpool-directory"
RFC: "false"
run: npx tsx index.ts

- uses: actions/upload-artifact@v4
Expand Down
80 changes: 54 additions & 26 deletions helpers/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { writeFile } from "fs/promises";
import twitter from "./twitter";
import { TwitterMap } from "..";

export const DEVPOOL_OWNER_NAME = process.env.DEVPOOL_OWNER_NAME!;
export const DEVPOOL_REPO_NAME = process.env.DEVPOOL_REPO_NAME!;
export const IS_RFC = JSON.parse(process.env.RFC!);
Comment on lines +10 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-null assertion operator is considered a bad practice because if the value is null then the app fails while the compiler is trying to make sure that even if the value is null the app works as expected (or at least throws meaningful errors). The value! syntax is not used anywhere in the codebase. Pls refactor accordingly.

Copy link
Member

@0x4007 0x4007 Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine that the linter settings are not in sync with our template here, given that this passed CI.

Perhaps this is technically our responsibility to handle these sort of problems.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine that the linter settings are not in sync with our template here, given that this passed CI.

Perhaps this is technically our responsibility to handle these sort of problems.

Seems you've already created a related issue ubiquity/ts-template#54


export type GitHubIssue = RestEndpointMethodTypes["issues"]["get"]["response"]["data"];
export type GitHubLabel = RestEndpointMethodTypes["issues"]["listLabelsOnIssue"]["response"]["data"][0];

Expand All @@ -23,8 +27,6 @@ export const projects = _projects as {
category?: Record<string, string>;
};

export const DEVPOOL_OWNER_NAME = "ubiquity";
export const DEVPOOL_REPO_NAME = "devpool-directory";
export enum LABELS {
PRICE = "Price",
UNAVAILABLE = "Unavailable",
Expand Down Expand Up @@ -129,12 +131,24 @@ export function getDevpoolIssueLabels(issue: GitHubIssue, projectUrl: string) {
// get owner and repo name from issue's URL because the repo name could be updated
const [ownerName, repoName] = getRepoCredentials(issue.html_url);

const pricing = getIssuePriceLabel(issue)

let devpoolIssueLabels: string[];

// default labels
const devpoolIssueLabels = [
getIssuePriceLabel(issue), // price
`Partner: ${ownerName}/${repoName}`, // partner
`id: ${issue.node_id}`, // id
];
if (pricing != "Pricing: not set") {
devpoolIssueLabels = [
pricing,
`Partner: ${ownerName}/${repoName}`, // partner
`id: ${issue.node_id}`, // id
];
}
else {
devpoolIssueLabels = [
`Partner: ${ownerName}/${repoName}`, // partner
`id: ${issue.node_id}`, // id
];
}

// if project is already assigned then add the "Unavailable" label
if (issue.assignee?.login) devpoolIssueLabels.push(LABELS.UNAVAILABLE);
Expand Down Expand Up @@ -380,8 +394,10 @@ export async function createDevPoolIssue(projectIssue: GitHubIssue, projectUrl:
// if the project issue is assigned to someone, then skip it
if (projectIssue.assignee) return;

// if issue doesn't have the "Price" label then skip it, no need to pollute repo with draft issues
if (!(projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE))) return;
// check if the issue is the same type as it should be
const hasPriceLabel = (projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE));
const hasCorrectPriceLabel = (IS_RFC && !hasPriceLabel) || (!IS_RFC && hasPriceLabel)
if (!hasCorrectPriceLabel) return;

// create a new issue
try {
Expand All @@ -399,15 +415,17 @@ export async function createDevPoolIssue(projectIssue: GitHubIssue, projectUrl:
return;
}

// post to social media
try {
const socialMediaText = getSocialMediaText(createdIssue.data);
const tweetId = await twitter.postTweet(socialMediaText);

twitterMap[createdIssue.data.node_id] = tweetId?.id ?? "";
await writeFile("./twitterMap.json", JSON.stringify(twitterMap));
} catch (err) {
console.error("Failed to post tweet: ", err);
// post to social media (only if it's not an RFC)
if (!IS_RFC) {
try {
const socialMediaText = getSocialMediaText(createdIssue.data);
const tweetId = await twitter.postTweet(socialMediaText);

twitterMap[createdIssue.data.node_id] = tweetId?.id ?? "";
await writeFile("./twitterMap.json", JSON.stringify(twitterMap));
} catch (err) {
console.error("Failed to post tweet: ", err);
}
}
} catch (err) {
console.error("Failed to create new issue: ", err);
Expand All @@ -426,7 +444,7 @@ export async function handleDevPoolIssue(
const labelRemoved = getDevpoolIssueLabels(projectIssue, projectUrl).filter((label) => label != LABELS.UNAVAILABLE);
const originals = devpoolIssue.labels.map((label) => (label as GitHubLabel).name);
const hasChanges = !areEqual(originals, labelRemoved);
const hasNoPriceLabels = !(projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE));
const hasPriceLabel = (projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE));

const metaChanges = {
// the title of the issue has changed
Expand All @@ -439,7 +457,7 @@ export async function handleDevPoolIssue(

await applyMetaChanges(metaChanges, devpoolIssue, projectIssue, isFork, labelRemoved, originals);

const newState = await applyStateChanges(projectIssues, projectIssue, devpoolIssue, hasNoPriceLabels);
const newState = await applyStateChanges(projectIssues, projectIssue, devpoolIssue, hasPriceLabel);

await applyUnavailableLabelToDevpoolIssue(
projectIssue,
Expand Down Expand Up @@ -481,7 +499,11 @@ async function applyMetaChanges(
}
}

async function applyStateChanges(projectIssues: GitHubIssue[], projectIssue: GitHubIssue, devpoolIssue: GitHubIssue, hasNoPriceLabels: boolean) {
async function applyStateChanges(projectIssues: GitHubIssue[], projectIssue: GitHubIssue, devpoolIssue: GitHubIssue, hasPriceLabel: boolean) {
const hasCorrectPriceLabel = (IS_RFC && !hasPriceLabel) || (!IS_RFC && hasPriceLabel)

// console.log(hasCorrectPriceLabel)

const stateChanges: StateChanges = {
// missing in the partners
forceMissing_Close: {
Expand All @@ -491,10 +513,16 @@ async function applyStateChanges(projectIssues: GitHubIssue[], projectIssue: Git
},
// no price labels set and open in the devpool
noPriceLabels_Close: {
cause: hasNoPriceLabels && devpoolIssue.state === "open",
cause: (!IS_RFC) && (!hasCorrectPriceLabel) && devpoolIssue.state === "open",
effect: "closed",
comment: "Closed (no price labels)",
},
// HAS price labels set and open in the RFC devpool
rfcPriceLabels_Close: {
cause: IS_RFC && (!hasCorrectPriceLabel) && devpoolIssue.state === "open",
effect: "closed",
comment: "Closed (has price labels)",
},
// it's closed, been merged and still open in the devpool
issueComplete_Close: {
cause: projectIssue.state === "closed" && devpoolIssue.state === "open" && !!projectIssue.pull_request?.merged_at,
Expand All @@ -519,20 +547,20 @@ async function applyStateChanges(projectIssues: GitHubIssue[], projectIssue: Git
effect: "closed",
comment: "Closed (assigned-open)",
},
// it's open, merged, unassigned, has price labels and is closed in the devpool
// it's open, merged, unassigned, has CORRECT price labels and is closed in the devpool
issueReopenedMerged_Open: {
cause:
projectIssue.state === "open" &&
devpoolIssue.state === "closed" &&
!!projectIssue.pull_request?.merged_at &&
!hasNoPriceLabels &&
hasCorrectPriceLabel &&
!projectIssue.assignee?.login,
effect: "open",
comment: "Reopened (merged)",
},
// it's open, unassigned, has price labels and is closed in the devpool
// it's open, unassigned, has CORRECT price labels and is closed in the devpool
issueUnassigned_Open: {
cause: projectIssue.state === "open" && devpoolIssue.state === "closed" && !projectIssue.assignee?.login && !hasNoPriceLabels,
cause: projectIssue.state === "open" && devpoolIssue.state === "closed" && !projectIssue.assignee?.login && hasCorrectPriceLabel,
effect: "open",
comment: "Reopened (unassigned)",
},
Expand Down
11 changes: 7 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import dotenv from "dotenv";
import {
DEVPOOL_OWNER_NAME,
DEVPOOL_REPO_NAME,
IS_RFC,
getAllIssues,
getIssueByLabel,
getProjectUrls,
Expand Down Expand Up @@ -35,7 +36,7 @@ async function main() {
}

// get devpool issues
const devpoolIssues: GitHubIssue[] = await getAllIssues(DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME);
const devpoolIssues: GitHubIssue[] = (await getAllIssues(DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME))

// aggregate projects.urls and opt settings
const projectUrls = await getProjectUrls();
Expand Down Expand Up @@ -74,10 +75,12 @@ async function main() {
}

// Calculate total rewards from devpool issues
const { rewards, tasks } = await calculateStatistics(await getAllIssues(DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME));
const statistics: Statistics = { rewards, tasks };
if (IS_RFC) {
const { rewards, tasks } = await calculateStatistics(await getAllIssues(DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME));
const statistics: Statistics = { rewards, tasks };

await writeTotalRewardsToGithub(statistics);
await writeTotalRewardsToGithub(statistics);
}
}

void (async () => {
Expand Down
55 changes: 55 additions & 0 deletions mocks/issue-devpool-template-rfc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"assignee": {
"login": "",
"avatar_url": "",
"email": "undefined",
"events_url": "",
"followers_url": "",
"following_url": "",
"gists_url": "",
"gravatar_id": null,
"html_url": "",
"id": 1,
"name": "undefined",
"node_id": "",
"organizations_url": "",
"received_events_url": "",
"repos_url": "",
"site_admin": false,
"starred_at": "",
"starred_url": "",
"subscriptions_url": "",
"type": "",
"url": ""
},
"author_association": "NONE",
"closed_at": null,
"comments": 0,
"comments_url": "",
"created_at": "",
"events_url": "",
"html_url": "https://github.com/ubiquity/devpool-rfc/issues/1",
"id": 1,
"labels_url": "",
"locked": false,
"milestone": null,
"node_id": "1",
"number": 1,
"repository_url": "https://github.com/ubiquity/devpool-rfc",
"state": "open",
"title": "issue",
"updated_at": "",
"url": "",
"user": null,
"owner": "ubiquity",
"repo": "devpool-rfc",
"labels": [
{
"name": "Time: 1h"
},
{
"name": "id: 2"
}
],
"body": "https://github.com/ubiquity/test-repo/issues/1"
}
52 changes: 52 additions & 0 deletions mocks/issue-template-rfc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"assignee": {
"login": "",
"avatar_url": "",
"email": "undefined",
"events_url": "",
"followers_url": "",
"following_url": "",
"gists_url": "",
"gravatar_id": null,
"html_url": "",
"id": 1,
"name": "undefined",
"node_id": "",
"organizations_url": "",
"received_events_url": "",
"repos_url": "",
"site_admin": false,
"starred_at": "",
"starred_url": "",
"subscriptions_url": "",
"type": "",
"url": ""
},
"author_association": "NONE",
"closed_at": null,
"comments": 0,
"comments_url": "",
"created_at": "",
"events_url": "",
"html_url": "https://github.com/ubiquity/test-repo/issues/1",
"id": 2,
"labels_url": "",
"locked": false,
"milestone": null,
"node_id": "2",
"number": 2,
"repository_url": "https://github.com/ubiquity/test-repo",
"state": "open",
"title": "issue",
"updated_at": "",
"url": "",
"user": null,
"owner": "ubiquity",
"repo": "test-repo",
"labels": [
{
"name": "Time: 1h"
}
],
"body": "body"
}
Loading
Loading