Skip to content

Commit

Permalink
Merge pull request ubiquity-os-marketplace#42 from gentlementlegen/fe…
Browse files Browse the repository at this point in the history
…at/label-gating

feat/label-gating
  • Loading branch information
gentlementlegen authored Nov 2, 2024
2 parents eb5b16e + a144021 commit 01a28b7
Show file tree
Hide file tree
Showing 21 changed files with 447 additions and 133 deletions.
6 changes: 3 additions & 3 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
"**/*.http",
"src/adapters/supabase/types/database.ts",
"bun.lockb",
"dist"
"dist/**"
],
"useGitignore": true,
"language": "en",
"words": [
"gentlementlegen",
"AUTHED",
"UNAUTHED",
"gentlementlegen",
"Authed",
"Tand",
"typeguard",
"dataurl",
"devpool",
"outdir",
Expand Down
17 changes: 2 additions & 15 deletions .github/workflows/compute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,11 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}

- name: Echo inputs
run: echo ${{ inputs.settings }}

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"

- uses: oven-sh/setup-bun@v1

- name: Install dependencies
run: yarn install

- name: Calling action
uses: ./
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
PLUGIN_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KERNEL_PUBLIC_KEY: ${{ secrets.KERNEL_PUBLIC_KEY }}
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,36 @@ Example of valid configuration:

```yml
- plugin: https://ubiquity-os-daemon-pricing.ubq.fi
type: github
with:
labels:
time:
- "Time: <1 Hour"
- "Time: <2 Hours"
- "Time: <4 Hours"
- "Time: <1 Day"
- "Time: <1 Week"
- name: "Time: <1 Hour"
collaboratorOnly: false
- name: "Time: <2 Hours"
collaboratorOnly: false
- name: "Time: <4 Hours"
collaboratorOnly: false
- name: "Time: <1 Day"
collaboratorOnly: false
- name: "Time: <1 Week"
collaboratorOnly: false
priority:
- "Priority: 1 (Normal)"
- "Priority: 2 (Medium)"
- "Priority: 3 (High)"
- "Priority: 4 (Urgent)"
- "Priority: 5 (Emergency)"
- name: "Priority: 1 (Normal)"
collaboratorOnly: false
- name: "Priority: 2 (Medium)"
collaboratorOnly: true
- name: "Priority: 3 (High)"
collaboratorOnly: false
- name: "Priority: 4 (Urgent)"
collaboratorOnly: false
- name: "Priority: 5 (Emergency)"
collaboratorOnly: false
basePriceMultiplier: 1
publicAccessControl:
setLabel: true
fundExternalClosedIssue: false
globalConfigUpdate:
excludeRepos: ["devpool-directory", "devpool-directory-private"]
```
## Running locally
Expand Down
13 changes: 3 additions & 10 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
name: "Delegate Compute"
description: "UbiquityOS Delegated Compute Action"
outputs:
result: # id of output
result:
description: "The result of a event handler"
value: ${{ steps.mainHandler.outputs.result }}
runs:
using: "composite"
steps:
- run: cd ${{ github.action_path }}
shell: bash
- run: bun install
shell: bash
- run: bun start
shell: bash
id: mainHandler
using: "node20"
main: "dist/index.js"
8 changes: 4 additions & 4 deletions dist/index.js

Large diffs are not rendered by default.

26 changes: 24 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,36 @@
"default": [],
"type": "array",
"items": {
"type": "string"
"type": "object",
"properties": {
"name": {
"description": "The display name of the label",
"type": "string"
},
"collaboratorOnly": {
"default": false,
"description": "Whether the label is only available to collaborators",
"type": "boolean"
}
},
"required": ["name"]
}
},
"priority": {
"default": [],
"type": "array",
"items": {
"type": "string"
"type": "object",
"properties": {
"name": {
"type": "string"
},
"collaboratorOnly": {
"default": false,
"type": "boolean"
}
},
"required": ["name"]
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"engines": {
"node": ">=20.10.0"
},
"type": "module",
"scripts": {
"worker": "wrangler dev --env dev --port 4000",
"start": "tsx src/index.ts",
Expand Down Expand Up @@ -71,11 +70,11 @@
"lint-staged": "^15.2.2",
"npm-run-all": "^4.1.5",
"prettier": "^3.2.5",
"supabase": "1.165.0",
"supabase": "^1.207.9",
"ts-jest": "29.1.2",
"ts-node": "10.9.2",
"tsx": "^4.7.1",
"typescript": "5.6.2",
"typescript": "5.5.4",
"wrangler": "^3.83.0"
},
"lint-staged": {
Expand Down
62 changes: 62 additions & 0 deletions src/handlers/get-label-changes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ContextPlugin } from "../types/plugin-input";
import { isPushEvent } from "../types/typeguards";

export async function getLabelsChanges(context: ContextPlugin) {
if (!isPushEvent(context)) {
context.logger.debug("Not a push event");
return false;
}
const {
logger,
payload: { repository, head_commit: headCommit },
} = context;
const commitSha = headCommit?.id;
let commitData;

if (!commitSha) {
throw new Error("No commit sha found");
}
const owner = repository.owner?.login;

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

try {
commitData = await context.octokit.rest.repos.getCommit({
owner,
repo: repository.name,
ref: commitSha,
mediaType: {
format: "diff",
},
});
} catch (err: unknown) {
logger.debug("Commit sha error.", { err });
}

if (!commitData) {
throw new Error("No commit data found");
}

const data = commitData.data as unknown as string;
const changes = data.split("\n");

const newLabelsRegex = /\+\s*collaboratorOnly:\s*(\S+)/;
const oldLabelsRegex = /-\s*collaboratorOnly:\s*(\S+)/;

const newLabels = extractLabels(changes, newLabelsRegex);
const previousLabels = extractLabels(changes, oldLabelsRegex);

if (!previousLabels && !newLabels) {
logger.error("No label changes found in the diff");
}

return !!previousLabels?.length || !!newLabels?.length;
}

function extractLabels(changes: string[], regex: RegExp): string | undefined {
const matchedLine = changes?.find((line) => regex.test(line));
const match = matchedLine?.match(regex);
return match ? match[1] : undefined;
}
14 changes: 9 additions & 5 deletions src/handlers/global-config-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { ContextPlugin } from "../types/plugin-input";
import { isPushEvent } from "../types/typeguards";
import { isConfigModified } from "./check-modified-base-rate";
import { getBaseRateChanges } from "./get-base-rate-changes";
import { setPriceLabel } from "./pricing-label";
import { getLabelsChanges } from "./get-label-changes";
import { syncPriceLabelsToConfig } from "./sync-labels-to-config";
import { setPriceLabel } from "./pricing-label";

async function isAuthed(context: ContextPlugin): Promise<boolean> {
if (!isPushEvent(context)) {
Expand Down Expand Up @@ -51,14 +52,17 @@ export async function globalLabelUpdate(context: ContextPlugin) {
}

const rates = await getBaseRateChanges(context);
const didLabelsChange = await getLabelsChanges(context);

if (rates.newBaseRate === null) {
logger.error("No new base rate found in the diff");
if (rates.newBaseRate === null && !didLabelsChange) {
logger.error("No changes found in the diff, skipping.");
return;
}

logger.info(`Updating base rate from ${rates.previousBaseRate} to ${rates.newBaseRate}`);
config.basePriceMultiplier = rates.newBaseRate;
if (rates.newBaseRate !== null) {
logger.info(`Updating base rate from ${rates.previousBaseRate} to ${rates.newBaseRate}`);
config.basePriceMultiplier = rates.newBaseRate;
}

const repos = await listOrgRepos(context);

Expand Down
35 changes: 21 additions & 14 deletions src/handlers/pricing-label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { labelAccessPermissionsCheck } from "../shared/permissions";
import { Label, UserType } from "../types/github";
import { getPrice } from "../shared/pricing";
import { handleParentIssue, isParentIssue, sortLabelsByValue } from "./handle-parent-issue";
import { AssistivePricingSettings, ContextPlugin } from "../types/plugin-input";
import { AssistivePricingSettings, ContextPlugin, COLLABORATOR_ONLY_DESCRIPTION } from "../types/plugin-input";
import { isIssueLabelEvent } from "../types/typeguards";

export async function onLabelChangeSetPricing(context: ContextPlugin): Promise<void> {
Expand Down Expand Up @@ -82,9 +82,6 @@ export async function setPriceLabel(context: ContextPlugin, issueLabels: Label[]
return;
}

for (const timeLabel of recognizedLabels.time) {
}

for (const priorityLabel of recognizedLabels.priority) {
if (priorityLabel.name !== minLabels.time?.name) {
await removeLabelFromIssue(context, priorityLabel.name);
Expand All @@ -94,7 +91,7 @@ export async function setPriceLabel(context: ContextPlugin, issueLabels: Label[]
const targetPriceLabel = getPrice(context, minLabels.time, minLabels.priority);

if (targetPriceLabel) {
await handleTargetPriceLabel(context, targetPriceLabel, labelNames);
await handleTargetPriceLabel(context, { name: targetPriceLabel, description: null }, labelNames);
await clearAllPriceLabelsOnIssue(context);
logger.info(`Skipping action...`);
}
Expand All @@ -105,9 +102,19 @@ function getRecognizedLabels(labels: Label[], settings: AssistivePricingSettings
return (typeof label === "string" || typeof label === "object") && configLabels.some((configLabel) => configLabel === label.name);
}

const recognizedTimeLabels: Label[] = labels.filter((label: Label) => isRecognizedLabel(label, settings.labels.time));
const recognizedTimeLabels: Label[] = labels.filter((label: Label) =>
isRecognizedLabel(
label,
settings.labels.time.map((o) => o.name)
)
);

const recognizedPriorityLabels: Label[] = labels.filter((label: Label) => isRecognizedLabel(label, settings.labels.priority));
const recognizedPriorityLabels: Label[] = labels.filter((label: Label) =>
isRecognizedLabel(
label,
settings.labels.priority.map((o) => o.name)
)
);

return { time: recognizedTimeLabels, priority: recognizedPriorityLabels };
}
Expand All @@ -119,21 +126,21 @@ function getMinLabels(recognizedLabels: { time: Label[]; priority: Label[] }) {
return { time: minTimeLabel, priority: minPriorityLabel };
}

async function handleTargetPriceLabel(context: ContextPlugin, targetPriceLabel: string, labelNames: string[]) {
async function handleTargetPriceLabel(context: ContextPlugin, targetPriceLabel: Pick<Label, "name" | "description">, labelNames: string[]) {
const { repository } = context.payload;
if (repository.name === "devpool-directory") {
targetPriceLabel = targetPriceLabel.replace("Price: ", "Pricing: ");
targetPriceLabel.name = targetPriceLabel.name.replace("Price: ", "Pricing: ");
}
const _targetPriceLabel = labelNames.find((name) => name.includes(targetPriceLabel));
const _targetPriceLabel = labelNames.find((name) => name.includes(targetPriceLabel.name));

if (_targetPriceLabel) {
await handleExistingPriceLabel(context, targetPriceLabel);
await handleExistingPriceLabel(context, targetPriceLabel.name);
} else {
const allLabels = await listLabelsForRepo(context);
if (allLabels.filter((i) => i.name.includes(targetPriceLabel)).length === 0) {
await createLabel(context, targetPriceLabel, "price");
if (allLabels.filter((i) => i.name.includes(targetPriceLabel.name)).length === 0) {
await createLabel(context, targetPriceLabel.name, "price", targetPriceLabel.description ? COLLABORATOR_ONLY_DESCRIPTION : undefined);
}
await addPriceLabelToIssue(context, targetPriceLabel);
await addPriceLabelToIssue(context, targetPriceLabel.name);
}
}

Expand Down
Loading

0 comments on commit 01a28b7

Please sign in to comment.