Skip to content

Commit

Permalink
Merge pull request #116 from gentlementlegen/fix/member-role
Browse files Browse the repository at this point in the history
fix: member role inside of given repository checks
  • Loading branch information
gentlementlegen authored Jan 4, 2025
2 parents 8431a86 + cb8ad20 commit 89170cf
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 28 deletions.
16 changes: 3 additions & 13 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,7 @@
"unassignment",
"unassignments"
],
"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}"
]
"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}"]
}
3 changes: 2 additions & 1 deletion .github/workflows/update-configuration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ jobs:
sourcemap: false
pluginEntry: ${{ github.workspace }}/src/index.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ To configure your Ubiquity Kernel to run this plugin, add the following to the `
rolesWithReviewAuthority: ["MEMBER", "OWNER"]
requiredLabelsToStart:
- name: "Priority: 5 (Emergency)"
roles: ["admin", "collaborator"]
roles: ["admin", "collaborator", "write"]
```
# Testing
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
"roles": {
"description": "The list of allowed roles to start the task with the given label.",
"uniqueItems": true,
"default": ["admin", "member", "collaborator", "contributor", "owner", "billing_manager"],
"default": ["admin", "member", "collaborator", "contributor", "owner", "billing_manager", "write", "read"],
"type": "array",
"items": {
"anyOf": [
Expand All @@ -165,6 +165,14 @@
{
"const": "billing_manager",
"type": "string"
},
{
"const": "read",
"type": "string"
},
{
"const": "write",
"type": "string"
}
]
}
Expand Down
38 changes: 31 additions & 7 deletions src/handlers/shared/get-user-task-limit-and-role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface MatchingUserProps {

export async function getUserRoleAndTaskLimit(context: Context, user: string): Promise<MatchingUserProps> {
const orgLogin = context.payload.organization?.login;
const { config, logger } = context;
const { config, logger, octokit } = context;
const { maxConcurrentTasks } = config;

const minUserTaskLimit = Object.entries(maxConcurrentTasks).reduce((minTask, [role, limit]) => (limit < minTask.limit ? { role, limit } : minTask), {
Expand All @@ -21,15 +21,39 @@ export async function getUserRoleAndTaskLimit(context: Context, user: string): P
throw new Error("Invalid organization name");
}

const response = await context.octokit.rest.orgs.getMembershipForUser({
org: orgLogin,
let role;
let limit;

try {
const response = await octokit.rest.orgs.getMembershipForUser({
org: orgLogin,
username: user,
});
role = response.data.role.toLowerCase();
limit = maxConcurrentTasks[role] ?? Infinity;
return { role, limit };
} catch (err) {
logger.error("Could not get user membership", { err });
}

// If we failed to get organization membership, narrow down to repo role
const permissionLevel = await octokit.rest.repos.getCollaboratorPermissionLevel({
username: user,
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
});
role = permissionLevel.data.role_name?.toLowerCase();
context.logger.debug(`Retrieved collaborator permission level for ${user}.`, {
user,
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
isAdmin: permissionLevel.data.user?.permissions?.admin,
role,
data: permissionLevel.data,
});
limit = maxConcurrentTasks[role] ?? Infinity;

const role = response.data.role.toLowerCase();
const limit = maxConcurrentTasks[role];

return limit ? { role, limit } : minUserTaskLimit;
return { role, limit };
} catch (err) {
logger.error("Could not get user role", { err });
return minUserTaskLimit;
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createPlugin } from "@ubiquity-os/plugin-sdk";
import { Manifest } from "@ubiquity-os/plugin-sdk/manifest";
import { LogLevel } from "@ubiquity-os/ubiquity-os-logger";
import { LOG_LEVEL, LogLevel } from "@ubiquity-os/ubiquity-os-logger";
import type { ExecutionContext } from "hono";
import manifest from "../manifest.json";
import { createAdapters } from "./adapters";
Expand All @@ -25,7 +25,7 @@ export default {
envSchema: envSchema,
postCommentOnError: true,
settingsSchema: pluginSettingsSchema,
logLevel: env.LOG_LEVEL as LogLevel,
logLevel: (env.LOG_LEVEL as LogLevel) ?? LOG_LEVEL.INFO,
kernelPublicKey: env.KERNEL_PUBLIC_KEY,
bypassSignatureVerification: process.env.NODE_ENV === "local",
}
Expand Down
4 changes: 2 additions & 2 deletions src/types/plugin-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ export function stringLiteralUnion<T extends string[]>(values: [...T]): Union<In
return T.Union(literals) as Union<IntoStringLiteralUnion<T>>;
}

const roles = stringLiteralUnion(["admin", "member", "collaborator", "contributor", "owner", "billing_manager"]);
const roles = stringLiteralUnion(["admin", "member", "collaborator", "contributor", "owner", "billing_manager", "read", "write"]);

const requiredLabel = T.Object({
name: T.String({ description: "The name of the required labels to start the task." }),
roles: T.Array(roles, {
description: "The list of allowed roles to start the task with the given label.",
uniqueItems: true,
default: ["admin", "member", "collaborator", "contributor", "owner", "billing_manager"],
default: ["admin", "member", "collaborator", "contributor", "owner", "billing_manager", "write", "read"],
}),
});

Expand Down
50 changes: 50 additions & 0 deletions tests/roles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, it } from "@jest/globals";
import { Logs } from "@ubiquity-os/ubiquity-os-logger";
import { getUserRoleAndTaskLimit } from "../src/handlers/shared/get-user-task-limit-and-role";
import { Context } from "../src/types";

describe("Role tests", () => {
it("Should retrieve the user role from organization", async () => {
const maxConcurrentTasks = {
contributor: 2,
admin: 100,
read: 1,
};
const ctx = {
payload: {
organization: {
login: "ubiquity-os-marketplace",
},
repository: {
owner: {
login: "ubiquity-os-marketplace",
},
name: "command-start-stop",
},
},
config: {
maxConcurrentTasks,
},
logger: new Logs("debug"),
octokit: {
rest: {
orgs: {
getMembershipForUser: jest.fn(() => ({ data: { role: "admin" } })),
},
},
},
} as unknown as Context;

let result = await getUserRoleAndTaskLimit(ctx, "ubiquity-os");
expect(result).toEqual({ limit: maxConcurrentTasks.admin, role: "admin" });
ctx.octokit = {
rest: {
repos: {
getCollaboratorPermissionLevel: jest.fn(() => ({ data: { role_name: "read" } })),
},
},
} as unknown as Context["octokit"];
result = await getUserRoleAndTaskLimit(ctx, "ubiquity-os");
expect(result).toEqual({ limit: maxConcurrentTasks.read, role: "read" });
});
});

0 comments on commit 89170cf

Please sign in to comment.