Skip to content

Commit

Permalink
chore: paginate listRepoLabels, formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed Sep 28, 2024
1 parent 590612d commit 9f3d388
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 168 deletions.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"useGitignore": true,
"language": "en",
"words": [
"UNAUTHED",
"gentlementlegen",
"Authed",
"Tand",
Expand Down
72 changes: 34 additions & 38 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,52 @@

## [1.0.2](https://github.com/ubiquibot/assistive-pricing/compare/v1.0.1...v1.0.2) (2024-08-20)


### Bug Fixes

* temporarily disable auth ([97c8b36](https://github.com/ubiquibot/assistive-pricing/commit/97c8b364381d7bb1abf09ffe10f7f88a4ad9f4c6))
- temporarily disable auth ([97c8b36](https://github.com/ubiquibot/assistive-pricing/commit/97c8b364381d7bb1abf09ffe10f7f88a4ad9f4c6))

## [1.0.1](https://github.com/ubiquibot/assistive-pricing/compare/v1.0.0...v1.0.1) (2024-08-20)


### Bug Fixes

* updated manifest.json ([3aa6c14](https://github.com/ubiquibot/assistive-pricing/commit/3aa6c14b3d250b7bb53a2ca4828049cf02318b8d))
- updated manifest.json ([3aa6c14](https://github.com/ubiquibot/assistive-pricing/commit/3aa6c14b3d250b7bb53a2ca4828049cf02318b8d))

## 1.0.0 (2024-07-08)


### Features

* access and label tables ([78d96d9](https://github.com/ubiquibot/assistive-pricing/commit/78d96d9485a79fc8c5d984d6967ecc90d86e3d64))
* action inputs ([abca8f0](https://github.com/ubiquibot/assistive-pricing/commit/abca8f0d5b5fc353fb314f6d12e7a4db179dcd61))
* added release-please.yml workflow ([a494891](https://github.com/ubiquibot/assistive-pricing/commit/a4948917b8a00deaa2fd000ac50ed4052ab7a8bd))
* assistive pricing ([2728e2e](https://github.com/ubiquibot/assistive-pricing/commit/2728e2e102681deb30461e5b86a7648631d03276))
* check signature ([c149116](https://github.com/ubiquibot/assistive-pricing/commit/c149116af230ba3e0f441f7a87b5651ecd10499d))
* database type generation ([e2c0f39](https://github.com/ubiquibot/assistive-pricing/commit/e2c0f395ccc9b70e22a28d2e7b1e6ec906024b0d))
* env is now validated ([ecbf7ab](https://github.com/ubiquibot/assistive-pricing/commit/ecbf7abbed3ccc2c1bc1bc82f5d9c6f08c153036))
* generating supabase types on build ([7978c60](https://github.com/ubiquibot/assistive-pricing/commit/7978c606fc771b2642798ea815adbec30e582939))
* handle comment ([a4beb54](https://github.com/ubiquibot/assistive-pricing/commit/a4beb5422df78b97ac32cd3349774b44f18762f4))
* now runs on cloudflare worker ([94d5bb7](https://github.com/ubiquibot/assistive-pricing/commit/94d5bb710a90442db3642594c92049763464be6a))
* setup action ([0160a2f](https://github.com/ubiquibot/assistive-pricing/commit/0160a2fc0afdde4bf75fc94aab633f9c14b1c472))
* setup node and pnpm ([5d3c1c1](https://github.com/ubiquibot/assistive-pricing/commit/5d3c1c162405358fbb8e0bc7a50fe7ce37669803))
* supabase, typeguards ([63643dd](https://github.com/ubiquibot/assistive-pricing/commit/63643dd73cd67c601cf2720ff9e97203806718c4))
* typebox for settings schema ([32250fe](https://github.com/ubiquibot/assistive-pricing/commit/32250fedce4b0df64b8af33d8e5fe4274afba58d))

- access and label tables ([78d96d9](https://github.com/ubiquibot/assistive-pricing/commit/78d96d9485a79fc8c5d984d6967ecc90d86e3d64))
- action inputs ([abca8f0](https://github.com/ubiquibot/assistive-pricing/commit/abca8f0d5b5fc353fb314f6d12e7a4db179dcd61))
- added release-please.yml workflow ([a494891](https://github.com/ubiquibot/assistive-pricing/commit/a4948917b8a00deaa2fd000ac50ed4052ab7a8bd))
- assistive pricing ([2728e2e](https://github.com/ubiquibot/assistive-pricing/commit/2728e2e102681deb30461e5b86a7648631d03276))
- check signature ([c149116](https://github.com/ubiquibot/assistive-pricing/commit/c149116af230ba3e0f441f7a87b5651ecd10499d))
- database type generation ([e2c0f39](https://github.com/ubiquibot/assistive-pricing/commit/e2c0f395ccc9b70e22a28d2e7b1e6ec906024b0d))
- env is now validated ([ecbf7ab](https://github.com/ubiquibot/assistive-pricing/commit/ecbf7abbed3ccc2c1bc1bc82f5d9c6f08c153036))
- generating supabase types on build ([7978c60](https://github.com/ubiquibot/assistive-pricing/commit/7978c606fc771b2642798ea815adbec30e582939))
- handle comment ([a4beb54](https://github.com/ubiquibot/assistive-pricing/commit/a4beb5422df78b97ac32cd3349774b44f18762f4))
- now runs on cloudflare worker ([94d5bb7](https://github.com/ubiquibot/assistive-pricing/commit/94d5bb710a90442db3642594c92049763464be6a))
- setup action ([0160a2f](https://github.com/ubiquibot/assistive-pricing/commit/0160a2fc0afdde4bf75fc94aab633f9c14b1c472))
- setup node and pnpm ([5d3c1c1](https://github.com/ubiquibot/assistive-pricing/commit/5d3c1c162405358fbb8e0bc7a50fe7ce37669803))
- supabase, typeguards ([63643dd](https://github.com/ubiquibot/assistive-pricing/commit/63643dd73cd67c601cf2720ff9e97203806718c4))
- typebox for settings schema ([32250fe](https://github.com/ubiquibot/assistive-pricing/commit/32250fedce4b0df64b8af33d8e5fe4274afba58d))

### Bug Fixes

* added secrets for Supabase generation ([ba46893](https://github.com/ubiquibot/assistive-pricing/commit/ba46893b28e114813ee576de61d32001cbc60502))
* added secrets for Supabase generation ([32a0d75](https://github.com/ubiquibot/assistive-pricing/commit/32a0d75c9e372fb13c9ab308265eaa398d529cdd))
* change from inputs to env ([63a6eee](https://github.com/ubiquibot/assistive-pricing/commit/63a6eeee3139018369134c10b3af256ea0aa9a71))
* check for membership before getting role ([3ac4014](https://github.com/ubiquibot/assistive-pricing/commit/3ac401451b86f1c993644288cf5e179f43a6e045))
* comment ([3945ae4](https://github.com/ubiquibot/assistive-pricing/commit/3945ae4c13d7c92260ffd5fc54a1c79758f3b4db))
* comment ([5d44e62](https://github.com/ubiquibot/assistive-pricing/commit/5d44e6203ad621745ce526a9ec08db8bcd3cda26))
* cspell ([92bfa6e](https://github.com/ubiquibot/assistive-pricing/commit/92bfa6e1303654e6e37c5b58776ba907413365b4))
* deployment and release are working properly ([d92e4c0](https://github.com/ubiquibot/assistive-pricing/commit/d92e4c04b325bd761c5558e61ebd945088f1da2a))
* eslint and cspell ([130ed5a](https://github.com/ubiquibot/assistive-pricing/commit/130ed5a1eabf2f11a81eca924d97ca140b6a3cf1))
* fixed TTY environment missing ([612c851](https://github.com/ubiquibot/assistive-pricing/commit/612c851b7c51cce07903a6fad0a72bb5053c2a1e))
* label type ([7278e3b](https://github.com/ubiquibot/assistive-pricing/commit/7278e3b14f1393cd0aa1b04b8fbb7a87e7a67b66))
* log instead of throw ([3c6ef5c](https://github.com/ubiquibot/assistive-pricing/commit/3c6ef5c3b338ac8953cbdb33313e9c071fa04e9b))
* permission for public set label ([9687b71](https://github.com/ubiquibot/assistive-pricing/commit/9687b718fd123623c3e825a648f777cb83f1b6a1))
* remove duplicates and ignore label already exists error ([1f2e3ff](https://github.com/ubiquibot/assistive-pricing/commit/1f2e3ff0027cf9b95b3d3c26a2455151452c57ad))
* sample request ([83a3d83](https://github.com/ubiquibot/assistive-pricing/commit/83a3d8385400cfd1cc85c7d3e2eb5d375144c859))
* spacing ([ead0dab](https://github.com/ubiquibot/assistive-pricing/commit/ead0dab367a1a4126bb73027c5a1e4153230577a))
* switch statement ([c429aa2](https://github.com/ubiquibot/assistive-pricing/commit/c429aa2eedaa583e769d8b2cc1196c32bbf768d8))
* tests ([4a9cfc3](https://github.com/ubiquibot/assistive-pricing/commit/4a9cfc3e98f283e54daf3c01d6e016d216eec658))
- added secrets for Supabase generation ([ba46893](https://github.com/ubiquibot/assistive-pricing/commit/ba46893b28e114813ee576de61d32001cbc60502))
- added secrets for Supabase generation ([32a0d75](https://github.com/ubiquibot/assistive-pricing/commit/32a0d75c9e372fb13c9ab308265eaa398d529cdd))
- change from inputs to env ([63a6eee](https://github.com/ubiquibot/assistive-pricing/commit/63a6eeee3139018369134c10b3af256ea0aa9a71))
- check for membership before getting role ([3ac4014](https://github.com/ubiquibot/assistive-pricing/commit/3ac401451b86f1c993644288cf5e179f43a6e045))
- comment ([3945ae4](https://github.com/ubiquibot/assistive-pricing/commit/3945ae4c13d7c92260ffd5fc54a1c79758f3b4db))
- comment ([5d44e62](https://github.com/ubiquibot/assistive-pricing/commit/5d44e6203ad621745ce526a9ec08db8bcd3cda26))
- cspell ([92bfa6e](https://github.com/ubiquibot/assistive-pricing/commit/92bfa6e1303654e6e37c5b58776ba907413365b4))
- deployment and release are working properly ([d92e4c0](https://github.com/ubiquibot/assistive-pricing/commit/d92e4c04b325bd761c5558e61ebd945088f1da2a))
- eslint and cspell ([130ed5a](https://github.com/ubiquibot/assistive-pricing/commit/130ed5a1eabf2f11a81eca924d97ca140b6a3cf1))
- fixed TTY environment missing ([612c851](https://github.com/ubiquibot/assistive-pricing/commit/612c851b7c51cce07903a6fad0a72bb5053c2a1e))
- label type ([7278e3b](https://github.com/ubiquibot/assistive-pricing/commit/7278e3b14f1393cd0aa1b04b8fbb7a87e7a67b66))
- log instead of throw ([3c6ef5c](https://github.com/ubiquibot/assistive-pricing/commit/3c6ef5c3b338ac8953cbdb33313e9c071fa04e9b))
- permission for public set label ([9687b71](https://github.com/ubiquibot/assistive-pricing/commit/9687b718fd123623c3e825a648f777cb83f1b6a1))
- remove duplicates and ignore label already exists error ([1f2e3ff](https://github.com/ubiquibot/assistive-pricing/commit/1f2e3ff0027cf9b95b3d3c26a2455151452c57ad))
- sample request ([83a3d83](https://github.com/ubiquibot/assistive-pricing/commit/83a3d8385400cfd1cc85c7d3e2eb5d375144c859))
- spacing ([ead0dab](https://github.com/ubiquibot/assistive-pricing/commit/ead0dab367a1a4126bb73027c5a1e4153230577a))
- switch statement ([c429aa2](https://github.com/ubiquibot/assistive-pricing/commit/c429aa2eedaa583e769d8b2cc1196c32bbf768d8))
- tests ([4a9cfc3](https://github.com/ubiquibot/assistive-pricing/commit/4a9cfc3e98f283e54daf3c01d6e016d216eec658))
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Assistive pricing",
"description": "Handles assistive pricing, and allows for users to modify labels.",
"ubiquity:listeners": [ "issues.labeled", "issues.unlabeled", "label.edited", "issue_comment.created" ],
"ubiquity:listeners": ["issues.labeled", "issues.unlabeled", "label.edited", "issue_comment.created", "push"],
"commands": {
"allow": {
"ubiquity:example": "/allow @user1 label",
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/get-base-rate-changes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function getBaseRateChanges(context: Context): Promise<Rates> {
if (!commitSha) {
throw new Error("No commit sha found");
}
const owner = repository.owner?.login
const owner = repository.owner?.login;

if (!owner) {
throw logger.error("No owner found in the repository");
Expand Down
2 changes: 0 additions & 2 deletions src/handlers/label-change.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ export async function watchLabelChange(context: Context) {
// check if user is authorized to make the change
const hasAccess = await hasLabelEditPermission(context, currentLabel, triggerUser);



await context.adapters.supabase.label.saveLabelChange({
previousLabel,
currentLabel,
Expand Down
8 changes: 4 additions & 4 deletions src/shared/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ export async function isUserAdminOrBillingManager(context: Context, username?: s
return false;
}

export async function addCommentToIssue(context: Context, message: string, issueNumber: number, owner_?: string, repo?: string) {
export async function addCommentToIssue(context: Context, message: string, issueNumber: number, repoOwner?: string, repo?: string) {
const payload = context.payload;
const owner = owner_ || payload.repository.owner?.login;
const owner = repoOwner || payload.repository.owner?.login;
if (!owner) throw context.logger.error("No owner found in the repository!");

try {
Expand All @@ -66,7 +66,7 @@ export async function listOrgRepos(context: Context) {
const response = await context.octokit.rest.repos.listForOrg({
org,
});
return response.data;
return response.data.filter((repo) => !repo.archived && !repo.disabled && !context.config.globalConfigUpdate?.excludeRepos.includes(repo.name));
} catch (err) {
throw context.logger.error("Listing org repos failed!", { err });
}
Expand All @@ -82,4 +82,4 @@ export async function listRepoIssues(context: Context, owner: string, repo: stri
} catch (err) {
throw context.logger.error("Listing repo issues failed!", { err });
}
}
}
80 changes: 26 additions & 54 deletions src/shared/label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,52 @@ import { Context } from "../types/context";
import { Label } from "../types/github";

// cspell:disable
const COLORS = { default: "ededed", price: "1f883d" };
export const COLORS = { default: "ededed", price: "1f883d" };
// cspell:enable

const NO_REPO_OWNER = "No owner found in the repository!";

export async function listLabelsForRepo(context: Context): Promise<Label[]> {
const payload = context.payload;
const { payload, octokit } = context;

const owner = payload.repository.owner?.login;
if (!owner) {
throw context.logger.error("No owner found in the repository!");
throw context.logger.error(NO_REPO_OWNER);
}

const res = await context.octokit.rest.issues.listLabelsForRepo({
// we need to paginate because the devpool has hundreds of labels
const res = await octokit.paginate(octokit.rest.issues.listLabelsForRepo, {
owner,
repo: payload.repository.name,
per_page: 100,
page: 1,
});

if (res.status === 200) {
return res.data;
if (res.length > 0) {
return res;
}

throw context.logger.error("Failed to fetch lists of labels", { status: res.status });
throw context.logger.error("Failed to fetch lists of labels", { status: 500 });
}

export async function createLabel(context: Context, name: string, labelType = "default" as keyof typeof COLORS): Promise<void> {
const payload = context.payload;

const color = name.startsWith("Price: ") ? COLORS.price : COLORS[labelType];
const owner = payload.repository.owner?.login;
if (!owner) {
throw context.logger.error("No owner found in the repository!");
throw context.logger.error(NO_REPO_OWNER);
}

await context.octokit.rest.issues.createLabel({
owner,
repo: payload.repository.name,
name,
color,
});
try {
await context.octokit.rest.issues.createLabel({
owner,
repo: payload.repository.name,
name,
color,
});
} catch (err) {
throw context.logger.error("Creating a label failed!", { err });
}
}

export async function clearAllPriceLabelsOnIssue(context: Context) {
Expand All @@ -51,7 +58,7 @@ export async function clearAllPriceLabelsOnIssue(context: Context) {

const labels = payload.issue.labels;
if (!labels) return;
const issuePriceLabels = labels.filter((label) => label.name.toString().startsWith("Price: "));
const issuePriceLabels = labels.filter((label) => label.name.toString().startsWith("Price: ") || label.name.toString().startsWith("Pricing: "));
if (!issuePriceLabels.length) return;

for (const label of issuePriceLabels) {
Expand All @@ -63,7 +70,7 @@ export async function clearAllPriceLabelsOnIssue(context: Context) {
name: label.name,
});
} catch (err: unknown) {
context.logger.error("Clearing all price labels failed!", { err });
throw context.logger.error("Clearing all price labels failed!", { err });
}
}
}
Expand All @@ -80,13 +87,8 @@ export async function addLabelToIssue(context: Context, labelName: string) {
issue_number: payload.issue.number,
labels: [labelName],
});

// Update color if it's a price label
if (labelName.startsWith("Price: ")) {
await updateLabelColor(context, labelName, COLORS.price);
}
} catch (err: unknown) {
context.logger.error("Adding a label to issue failed!", { err });
throw context.logger.error("Adding a label to issue failed!", { err });
}
}

Expand All @@ -104,36 +106,6 @@ export async function removeLabelFromIssue(context: Context, labelName: string)
name: labelName,
});
} catch (err: unknown) {
context.logger.error("Adding a label to issue failed!", { err });
}
}

async function updateLabelColor(context: Context, labelName: string, color: string) {
const payload = context.payload;
const owner = payload.repository.owner?.login;

if (!owner) {
throw context.logger.error("No owner found in the repository!");
}

const issueLabels = await listLabelsForRepo(context);
const label = issueLabels.find((label) => label.name === labelName);

if (!label) {
throw context.logger.error("Label not found!", { labelName });
}

if (label.color === color) return;

try {
await context.octokit.rest.issues.updateLabel({
owner,
repo: payload.repository.name,
name: label.name,
new_name: labelName,
color,
});
} catch (err: unknown) {
context.logger.error("Updating label color failed!", { err });
throw context.logger.error("Adding a label to issue failed!", { err });
}
}
48 changes: 32 additions & 16 deletions src/shared/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export async function labelAccessPermissionsCheck(context: Context) {
// event in plain english
let action;
if ("action" in payload) {
action = payload.action
action = payload.action;
} else {
throw new Error("No action found in payload")
throw new Error("No action found in payload");
}
const eventName = action === "labeled" ? "add" : "remove";
const labelName = payload.label.name;
Expand All @@ -52,23 +52,39 @@ export async function labelAccessPermissionsCheck(context: Context) {
});
return true;
} else {
logger.info("Checking access for labels", { repo: repo.full_name, user: sender, labelType });
// check permission
const { access, user } = context.adapters.supabase;
const userId = await user.getUserId(context, sender);
const accessible = await access.getAccess(userId, repo.id);
if (accessible && accessible.labels?.includes(labelType)) {
return true;
}
return handleInsufficientPrivileges(context, labelType, sender, repo, action, labelName, eventName);
}
}

async function handleInsufficientPrivileges(
context: Context,
labelType: string,
sender: string,
repo: Context["payload"]["repository"],
action: string,
labelName: string,
eventName: string
) {
const { logger, payload } = context;
logger.info("Checking access for labels", { repo: repo.full_name, user: sender, labelType });
// check permission
const { access, user } = context.adapters.supabase;
const userId = await user.getUserId(context, sender);
const accessible = await access.getAccess(userId, repo.id);
if (accessible && accessible.labels?.includes(labelType)) {
return true;
}

if (action === "labeled") {
await removeLabelFromIssue(context, labelName);
} else if (action === "unlabeled") {
await addLabelToIssue(context, labelName);
}
if (action === "labeled") {
await removeLabelFromIssue(context, labelName);
} else if (action === "unlabeled") {
await addLabelToIssue(context, labelName);
}

if ("issue" in payload && payload.issue) {
await addCommentToIssue(context, `@${sender}, You are not allowed to ${eventName} ${labelName}`, payload.issue.number);
logger.info("No access to edit label", { sender, label: labelName });
return false;
}

return false;
}
4 changes: 2 additions & 2 deletions src/types/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { AssistivePricingSettings } from "./plugin-input";
import { createAdapters } from "../adapters";
import { Logs } from "@ubiquity-dao/ubiquibot-logger";

export type SupportedEvents = "issues.labeled" | "issues.unlabeled" | "label.edited" | "issue_comment.created" | "push"
export type SupportedEvents = "issues.labeled" | "issues.unlabeled" | "label.edited" | "issue_comment.created" | "push";

export interface Context<T extends SupportedEvents | "issue_comment" = SupportedEvents> {
eventName: T;
payload: WebhookEvent<T>["payload"];
octokit: InstanceType<typeof Octokit>;
adapters: ReturnType<typeof createAdapters>;
config: AssistivePricingSettings;
logger: Logs
logger: Logs;
}
9 changes: 3 additions & 6 deletions src/types/plugin-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ export interface PluginInputs<T extends WebhookEventName = SupportedEvents> {

export const assistivePricingSettingsSchema = T.Object({
globalConfigUpdate: T.Optional(
T.Object(
{
excludeRepos: T.Array(T.String(), { default: [] }),
},
{ default: {} }
)
T.Object({
excludeRepos: T.Array(T.String()),
})
),
labels: T.Object(
{
Expand Down
Loading

0 comments on commit 9f3d388

Please sign in to comment.