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

Command interface #22

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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"],
"useGitignore": true,
"language": "en",
"words": ["Nektos", "dataurl", "devpool", "outdir", "servedir", "Supabase", "SUPABASE", "typebox", "ubiquibot", "Smee", "Rpcs"],
"words": ["Nektos", "dataurl", "devpool", "outdir", "servedir", "Supabase", "SUPABASE", "typebox", "ubiquibot", "Smee", "Rpcs", "hono"],
"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/knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const config: KnipConfig = {
ignore: ["**/__mocks__/**", "**/__fixtures__/**", "src/types/database.ts"],
ignoreExportsUsedInFile: true,
// eslint can also be safely ignored as per the docs: https://knip.dev/guides/handling-issues#eslint--jest
ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier", "@mswjs/data", "ts-node"],
ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier", "@mswjs/data", "ts-node", "hono"],
eslint: true,
};

Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/compute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
description: "Auth Token"
ref:
description: "Ref"
command:
required: true

jobs:
compute:
Expand Down
12 changes: 11 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@
"ubiquity:listeners": [
"issue_comment.created"
],
"skipBotEvents": true,
"commands": {
"wallet": {
"ubiquity:example": "/wallet ubq.eth",
"description": "Register your wallet address for payments."
"description": "Register your wallet address for payments.",
"parameters": {
"type": "object",
"properties": {
"walletAddress": {
"description": "Ethereum address or Ethereum Name Service",
"type": "string"
}
}
}
}
},
"configuration": {
Expand Down
29 changes: 13 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"knip-ci": "knip --no-exit-code --reporter json --config .github/knip.ts",
"prepare": "husky install",
"test": "jest --setupFiles dotenv/config --coverage",
"worker": "wrangler dev --env dev --port 4000",
"worker": "wrangler dev --env dev --port 4002",
"supabase:generate:local": "supabase gen types typescript --local > src/types/database.ts",
"supabase:generate:remote": "cross-env-shell \"supabase gen types typescript --project-id $SUPABASE_PROJECT_ID --schema public > src/types/database.ts\""
},
Expand All @@ -30,33 +30,30 @@
"open-source"
],
"dependencies": {
"@actions/core": "1.10.1",
"@actions/github": "6.0.0",
"@octokit/rest": "20.1.1",
"@octokit/webhooks": "13.2.7",
"@sinclair/typebox": "0.32.33",
"@sinclair/typebox": "0.34.3",
"@supabase/supabase-js": "2.43.5",
"@ubiquity-dao/rpc-handler": "1.3.0",
"@ubiquity-os/plugin-sdk": "^1.1.0",
"@ubiquity-os/ubiquity-os-logger": "^1.3.2",
"commander": "12.1.0",
"dotenv": "16.4.5",
"ethers": "6.13.1",
"typebox-validators": "0.3.5"
"ethers": "6.13.1"
},
"devDependencies": {
"@commitlint/cli": "19.3.0",
"@commitlint/config-conventional": "19.2.2",
"@cspell/dict-node": "5.0.1",
"@cspell/dict-software-terms": "3.4.6",
"@cspell/dict-typescript": "3.1.5",
"@eslint/js": "9.5.0",
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@cspell/dict-node": "^5.0.5",
"@cspell/dict-software-terms": "^4.1.15",
"@cspell/dict-typescript": "^3.1.2",
"@eslint/js": "9.14.0",
"@jest/globals": "29.7.0",
"@mswjs/data": "0.16.1",
"@types/node": "20.14.5",
"cross-env": "7.0.3",
"cspell": "8.9.0",
"dotenv-cli": "7.4.2",
"eslint": "9.5.0",
"eslint": "9.14.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-check-file": "2.8.0",
"eslint-plugin-prettier": "5.1.3",
Expand All @@ -74,8 +71,8 @@
"ts-node": "10.9.2",
"tsx": "4.15.6",
"typescript": "5.6.2",
"typescript-eslint": "7.13.1",
"wrangler": "3.79.0"
"typescript-eslint": "8.14.0",
"wrangler": "^3.87.0"
},
"lint-staged": {
"*.ts": [
Expand Down
9 changes: 9 additions & 0 deletions src/handlers/query-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ function extractEnsName(text: string) {
}
}

export async function handleCommand(context: Context) {
const { command } = context;
if (!command) {
throw new Error("Command is undefined");
}
const { walletAddress } = command.parameters;
await registerWallet(context, walletAddress);
}

export async function registerWallet(context: Context, body: string) {
const { payload, config, logger, adapters } = context;
const sender = payload.sender.login;
Expand Down
36 changes: 0 additions & 36 deletions src/handlers/validator.ts

This file was deleted.

75 changes: 22 additions & 53 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,24 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
import { Octokit } from "@octokit/rest";
import { Value } from "@sinclair/typebox/build/cjs/value";
import { envSchema, pluginSettingsSchema, PluginInputs, pluginSettingsValidator } from "./types";
import { createActionsPlugin } from "@ubiquity-os/plugin-sdk";
import { createAdapters } from "./adapters";
import { SupportedEvents } from "./types/context";
import { Env, envSchema } from "./types/env";
import { PluginSettings, pluginSettingsSchema } from "./types/plugin-inputs";
import { Command } from "./types/command";
import { plugin } from "./plugin";

/**
* How a GitHub action executes the plugin.
*/
export async function run() {
const payload = github.context.payload.inputs;

const env = Value.Decode(envSchema, payload.env);
const settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, JSON.parse(payload.settings)));

if (!pluginSettingsValidator.test(settings)) {
throw new Error("Invalid settings provided");
import { LogLevel } from "@ubiquity-os/ubiquity-os-logger";

createActionsPlugin<PluginSettings, Env, Command, SupportedEvents>(
(context) => {
return plugin({
...context,
adapters: {} as ReturnType<typeof createAdapters>,
});
},
{
envSchema: envSchema,
postCommentOnError: true,
settingsSchema: pluginSettingsSchema,
logLevel: (process.env.LOG_LEVEL as LogLevel) ?? "info",
kernelPublicKey: process.env.KERNEL_PUBLIC_KEY,
}

const inputs: PluginInputs = {
stateId: payload.stateId,
eventName: payload.eventName,
eventPayload: JSON.parse(payload.eventPayload),
settings,
authToken: payload.authToken,
ref: payload.ref,
};

await plugin(inputs, env);

return returnDataToKernel(inputs.authToken, inputs.stateId, {});
}

async function returnDataToKernel(repoToken: string, stateId: string, output: object) {
const octokit = new Octokit({ auth: repoToken });
await octokit.repos.createDispatchEvent({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
event_type: "return_data_to_ubiquibot_kernel",
client_payload: {
state_id: stateId,
output: JSON.stringify(output),
},
});
}

run()
.then((result) => {
core.setOutput("result", result);
})
.catch((error) => {
console.error(error);
core.setFailed(error);
});
).catch(console.error);
27 changes: 9 additions & 18 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
import { Octokit } from "@octokit/rest";
import { createClient } from "@supabase/supabase-js";
import { Logs } from "@ubiquity-os/ubiquity-os-logger";
import { CommanderError } from "commander";
import { createAdapters } from "./adapters";
import { CommandParser } from "./handlers/command-parser";
import { Env, PluginInputs } from "./types";
import { Context } from "./types";
import { addCommentToIssue } from "./utils";
import { handleCommand } from "./handlers/query-wallet";

/**
* How a worker executes the plugin.
*/
export async function plugin(inputs: PluginInputs, env: Env) {
const octokit = new Octokit({ auth: inputs.authToken });
const supabase = createClient(env.SUPABASE_URL, env.SUPABASE_KEY);

const context: Context = {
eventName: inputs.eventName,
payload: inputs.eventPayload,
config: inputs.settings,
octokit,
env,
logger: new Logs("info"),
adapters: {} as ReturnType<typeof createAdapters>,
};

export async function plugin(context: Context) {
const supabase = createClient(context.env.SUPABASE_URL, context.env.SUPABASE_KEY);
context.adapters = createAdapters(supabase, context);

if (context.command) {
await handleCommand(context);
return;
}

if (context.eventName === "issue_comment.created") {
const commandParser = new CommandParser(context);
try {
const args = inputs.eventPayload.comment.body.trim().split(/\s+/);
const args = context.payload.comment.body.trim().split(/\s+/);
await commandParser.parse(args);
} catch (err) {
if (err instanceof CommanderError) {
Expand Down
10 changes: 10 additions & 0 deletions src/types/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { StaticDecode, Type as T } from "@sinclair/typebox";

export const commandSchema = T.Object({
name: T.Literal("wallet"),
parameters: T.Object({
walletAddress: T.String(),
}),
});

export type Command = StaticDecode<typeof commandSchema>;
21 changes: 5 additions & 16 deletions src/types/context.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import { Octokit } from "@octokit/rest";
import { EmitterWebhookEvent as WebhookEvent, EmitterWebhookEventName as WebhookEventName } from "@octokit/webhooks";
import { Logs } from "@ubiquity-os/ubiquity-os-logger";
import { createAdapters } from "../adapters";
import { Env } from "./env";
import { PluginSettings } from "./plugin-inputs";
import { Context as PluginContext } from "@ubiquity-os/plugin-sdk";
import { Command } from "./command";

export type SupportedEventsU = "issue_comment.created";
export type SupportedEvents = "issue_comment.created";

export type SupportedEvents = {
[K in SupportedEventsU]: K extends WebhookEventName ? WebhookEvent<K> : never;
};

export interface Context<T extends SupportedEventsU = SupportedEventsU, TU extends SupportedEvents[T] = SupportedEvents[T]> {
eventName: T;
payload: TU["payload"];
octokit: InstanceType<typeof Octokit>;
export type Context<TEvents extends SupportedEvents = SupportedEvents> = PluginContext<PluginSettings, Env, Command, TEvents> & {
adapters: ReturnType<typeof createAdapters>;
config: PluginSettings;
env: Env;
logger: Logs;
}
};
6 changes: 2 additions & 4 deletions src/types/env.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Type as T } from "@sinclair/typebox";
import { StaticDecode } from "@sinclair/typebox";
import "dotenv/config";
import { StandardValidator } from "typebox-validators";

export const envSchema = T.Object({
SUPABASE_URL: T.String(),
SUPABASE_KEY: T.String(),
KERNEL_PUBLIC_KEY: T.Optional(T.String()),
LOG_LEVEL: T.Optional(T.String()),
});

export const envValidator = new StandardValidator(envSchema);

export type Env = StaticDecode<typeof envSchema>;
12 changes: 0 additions & 12 deletions src/types/plugin-inputs.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import { SupportedEvents, SupportedEventsU } from "./context";
import { StaticDecode, Type as T } from "@sinclair/typebox";
import { StandardValidator } from "typebox-validators";

export interface PluginInputs<T extends SupportedEventsU = SupportedEventsU, TU extends SupportedEvents[T] = SupportedEvents[T]> {
stateId: string;
eventName: T;
eventPayload: TU["payload"];
settings: PluginSettings;
authToken: string;
ref: string;
}

/**
* This should contain the properties of the bot config
Expand All @@ -21,6 +10,5 @@ export interface PluginInputs<T extends SupportedEventsU = SupportedEventsU, TU
export const pluginSettingsSchema = T.Object({
registerWalletWithVerification: T.Boolean({ default: false }),
});
export const pluginSettingsValidator = new StandardValidator(pluginSettingsSchema);

export type PluginSettings = StaticDecode<typeof pluginSettingsSchema>;
Loading