Skip to content

Commit

Permalink
Merge pull request #20 from ubq-testing/development
Browse files Browse the repository at this point in the history
  • Loading branch information
0x4007 authored Sep 12, 2024
2 parents 7ab97aa + f5cea4c commit 3684bec
Show file tree
Hide file tree
Showing 27 changed files with 485 additions and 386 deletions.
2 changes: 1 addition & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "**/*.http", "**/*.toml", "src/types/database.ts", "supabase/migrations/**", "tests/**"],
"useGitignore": true,
"language": "en",
"words": ["dataurl", "devpool", "outdir", "servedir", "typebox", "supabase", "ubiquibot", "mswjs", "luxon", "millis"],
"words": ["dataurl", "devpool", "outdir", "servedir", "typebox", "supabase", "ubiquibot", "mswjs", "luxon", "millis", "handl"],
"dictionaries": ["typescript", "node", "software-terms"],
"import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"],
"ignoreRegExpList": ["[0-9a-fA-F]{6}"]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- uses: cloudflare/wrangler-action@v3
with:
wranglerVersion: '3.57.0'
wranglerVersion: "3.57.0"
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
secrets: |
SUPABASE_URL
Expand Down
20 changes: 9 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@

## 1.0.0 (2024-07-09)


### Features

* added testing ([c834de9](https://github.com/ubiquibot/user-activity-watcher/commit/c834de9edefce23c11dc4d91ecc48d7e16ed3e5f))
* changed the time parsing to be with ms package ([99fa8f7](https://github.com/ubiquibot/user-activity-watcher/commit/99fa8f74524552b8dd17ae0dd6a66da3782abab3))
* database generation script ([6f19d4d](https://github.com/ubiquibot/user-activity-watcher/commit/6f19d4d0722dbcfd4e3b59ce1dddb94a550a20ac))
* database generation script ([fb4be18](https://github.com/ubiquibot/user-activity-watcher/commit/fb4be189de5c07794d05099acc9b61991f9813bf))
* linked pull request activity is now taken into account ([790d1c1](https://github.com/ubiquibot/user-activity-watcher/commit/790d1c12e3b1d716e72756e486723c3fe018d252))
* threshold can be expressed as human-readable strings ([df167d0](https://github.com/ubiquibot/user-activity-watcher/commit/df167d0b29335c1143ff6e1e6c2f11f0529e59c5))
* user get reminded and unassigned ([797cd6e](https://github.com/ubiquibot/user-activity-watcher/commit/797cd6e27788e119de27722118fbcf766ce4e79a))

- added testing ([c834de9](https://github.com/ubiquibot/user-activity-watcher/commit/c834de9edefce23c11dc4d91ecc48d7e16ed3e5f))
- changed the time parsing to be with ms package ([99fa8f7](https://github.com/ubiquibot/user-activity-watcher/commit/99fa8f74524552b8dd17ae0dd6a66da3782abab3))
- database generation script ([6f19d4d](https://github.com/ubiquibot/user-activity-watcher/commit/6f19d4d0722dbcfd4e3b59ce1dddb94a550a20ac))
- database generation script ([fb4be18](https://github.com/ubiquibot/user-activity-watcher/commit/fb4be189de5c07794d05099acc9b61991f9813bf))
- linked pull request activity is now taken into account ([790d1c1](https://github.com/ubiquibot/user-activity-watcher/commit/790d1c12e3b1d716e72756e486723c3fe018d252))
- threshold can be expressed as human-readable strings ([df167d0](https://github.com/ubiquibot/user-activity-watcher/commit/df167d0b29335c1143ff6e1e6c2f11f0529e59c5))
- user get reminded and unassigned ([797cd6e](https://github.com/ubiquibot/user-activity-watcher/commit/797cd6e27788e119de27722118fbcf766ce4e79a))

### Bug Fixes

* moved get env outside of main file ([cb55e61](https://github.com/ubiquibot/user-activity-watcher/commit/cb55e610d5ec2d7dd936f97155f2cc1814c1302d))
* updated Jest test comment ([d6d5e28](https://github.com/ubiquibot/user-activity-watcher/commit/d6d5e2881a106568f1b2eb6ba9710041dba75950))
- moved get env outside of main file ([cb55e61](https://github.com/ubiquibot/user-activity-watcher/commit/cb55e610d5ec2d7dd936f97155f2cc1814c1302d))
- updated Jest test comment ([d6d5e28](https://github.com/ubiquibot/user-activity-watcher/commit/d6d5e2881a106568f1b2eb6ba9710041dba75950))
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
# @ubiquibot/user-activity-watcher

Watches user activity on issues, sends reminders on deadlines, and eventually unassigns inactive user to ensure that
Watches user activity on issues, sends reminders on deadlines, and eventually unassigns inactive user to ensure that
tasks don't stall, and subtracts XP.

## Setup

```shell
yarn install
```

### Database

To start a local instance, run

```shell
supabase start
```

Afterward, you can generate types for full auto-completion with

```shell
yarn supabase:generate:local
```

### Test

To start Jest testing, run

```shell
yarn test
```

## Valid configuration

```yaml
- plugin: ubiquibot/user-activity-watcher
type: github
with:
disqualification: "7 days"
warning: "3.5 days"
watch:
optOut:
watch:
optOut:
- "repoName"
- "repoName2"
```
2 changes: 1 addition & 1 deletion graphql.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ schema:
headers:
Authorization: Bearer ${GITHUB_TOKEN}
documents: src/handlers/collect-linked-pulls.ts
projects: {}
projects: {}
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "User activity watcher",
"description": "Watches user activity on issues, sends reminders on deadlines, and unassign inactive users.",
"ubiquity:listeners": [ "pull_request_review_comment.created", "issue_comment.created", "push" ]
"ubiquity:listeners": ["pull_request_review_comment.created", "issue_comment.created", "push"]
}
50 changes: 27 additions & 23 deletions src/handlers/collect-linked-pulls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PullRequest, User, validate } from "@octokit/graphql-schema";

type closedByPullRequestsReferences = {
node: Pick<PullRequest, "url" | "title" | "number" | "state" | "body"> & Pick<User, "login" | "id">;
}
};

type IssueWithClosedByPRs = {
repository: {
Expand All @@ -13,32 +13,33 @@ type IssueWithClosedByPRs = {
};
};
};
}
};

const query = /* GraphQL */ `
query collectLinkedPullRequests($owner: String!, $repo: String!, $issue_number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $issue_number) {
closedByPullRequestsReferences(first: 100, includeClosedPrs: true) {
edges {
node {
url
title
body
state
number
author {
login
... on User {
id: databaseId
query collectLinkedPullRequests($owner: String!, $repo: String!, $issue_number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $issue_number) {
closedByPullRequestsReferences(first: 100, includeClosedPrs: true) {
edges {
node {
url
title
body
state
number
author {
login
... on User {
id: databaseId
}
}
}
}
}
}
}
}
}`
`;

const queryErrors = validate(query);

Expand All @@ -50,11 +51,14 @@ if (queryErrors.length > 1) {
throw new Error(`Invalid query: ${queryErrors.join(", ")}`);
}

export async function collectLinkedPullRequests(context: Context, issue: {
owner: string;
repo: string;
issue_number: number;
}) {
export async function collectLinkedPullRequests(
context: Context,
issue: {
owner: string;
repo: string;
issue_number: number;
}
) {
const { owner, repo, issue_number } = issue;
const result = await context.octokit.graphql<IssueWithClosedByPRs>(query, {
owner,
Expand Down
62 changes: 31 additions & 31 deletions src/handlers/watch-user-activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,44 @@ import { Context } from "../types/context";
import { ListForOrg, ListIssueForRepo } from "../types/github-types";

export async function watchUserActivity(context: Context) {
const { logger } = context;
const { logger } = context;

const repos = await getWatchedRepos(context);
const repos = await getWatchedRepos(context);

if (!repos?.length) {
logger.info("No watched repos have been found, no work to do.");
return false;
}
if (!repos?.length) {
logger.info("No watched repos have been found, no work to do.");
return false;
}

for (const repo of repos) {
await updateReminders(context, repo);
}
for (const repo of repos) {
await updateReminders(context, repo);
}

return true;
return true;
}

async function updateReminders(context: Context, repo: ListForOrg["data"][0]) {
const { logger, octokit, payload } = context;
const owner = payload.repository.owner?.login;
if (!owner) {
throw new Error("No owner found in the payload");
const { logger, octokit, payload } = context;
const owner = payload.repository.owner?.login;
if (!owner) {
throw new Error("No owner found in the payload");
}
const issues = (await octokit.paginate(octokit.rest.issues.listForRepo, {
owner,
repo: repo.name,
per_page: 100,
state: "open",
})) as ListIssueForRepo[];

for (const issue of issues) {
// I think we can safely ignore the following
if (issue.draft || issue.pull_request || issue.locked || issue.state !== "open") {
continue;
}
const issues = (await octokit.paginate(octokit.rest.issues.listForRepo, {
owner,
repo: repo.name,
per_page: 100,
state: "open",
})) as ListIssueForRepo[];

for (const issue of issues) {
// I think we can safely ignore the following
if (issue.draft || issue.pull_request || issue.locked || issue.state !== "open") {
continue;
}

if (issue.assignees?.length || issue.assignee) {
logger.debug(`Checking assigned issue: ${issue.html_url}`);
await updateTaskReminder(context, repo, issue);
}

if (issue.assignees?.length || issue.assignee) {
logger.debug(`Checking assigned issue: ${issue.html_url}`);
await updateTaskReminder(context, repo, issue);
}
}
}
41 changes: 21 additions & 20 deletions src/helpers/get-assignee-activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,26 @@ import { GitHubListEvents, ListIssueForRepo } from "../types/github-types";
* Retrieves all the activity for users that are assigned to the issue. Also takes into account linked pull requests.
*/
export async function getAssigneesActivityForIssue(context: Context, issue: ListIssueForRepo, assigneeIds: number[]) {
const gitHubUrl = parseIssueUrl(issue.html_url);
const issueEvents: GitHubListEvents[] = await context.octokit.paginate(context.octokit.rest.issues.listEvents, {
owner: gitHubUrl.owner,
repo: gitHubUrl.repo,
issue_number: gitHubUrl.issue_number,
per_page: 100,
const gitHubUrl = parseIssueUrl(issue.html_url);
const issueEvents: GitHubListEvents[] = await context.octokit.paginate(context.octokit.rest.issues.listEvents, {
owner: gitHubUrl.owner,
repo: gitHubUrl.repo,
issue_number: gitHubUrl.issue_number,
per_page: 100,
});
const linkedPullRequests = await collectLinkedPullRequests(context, gitHubUrl);
for (const linkedPullRequest of linkedPullRequests) {
const { owner, repo, issue_number } = parseIssueUrl(linkedPullRequest.url || "");
const events = await context.octokit.paginate(context.octokit.rest.issues.listEvents, {
owner,
repo,
issue_number,
per_page: 100,
});
const linkedPullRequests = await collectLinkedPullRequests(context, gitHubUrl);
for (const linkedPullRequest of linkedPullRequests) {
const { owner, repo, issue_number } = parseIssueUrl(linkedPullRequest.url || "");
const events = await context.octokit.paginate(context.octokit.rest.issues.listEvents, {
owner,
repo,
issue_number,
per_page: 100,
});
issueEvents.push(...events);
}
issueEvents.push(...events);
}

return issueEvents.filter((o) => o.actor && o.actor.id && assigneeIds.includes(o.actor.id))
.sort((a, b) => DateTime.fromISO(b.created_at).toMillis() - DateTime.fromISO(a.created_at).toMillis());
}
return issueEvents
.filter((o) => o.actor && o.actor.id && assigneeIds.includes(o.actor.id))
.sort((a, b) => DateTime.fromISO(b.created_at).toMillis() - DateTime.fromISO(a.created_at).toMillis());
}
2 changes: 1 addition & 1 deletion src/helpers/github-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export function parseIssueUrl(url: string): { owner: string; repo: string; issue
repo: path[2],
issue_number: Number(path[4]),
};
}
}
Loading

0 comments on commit 3684bec

Please sign in to comment.