Skip to content

Commit

Permalink
feat: merge
Browse files Browse the repository at this point in the history
  • Loading branch information
whilefoo committed Nov 9, 2024
2 parents 164f247 + f09bf82 commit 6d24748
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 43 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ bun dev
6. **Deploy the Kernel:**
- Execute `bun run deploy-dev` to deploy the kernel.

7. **Setup database (optional)**
- You can set up your local database by going through [this repository](https://github.com/ubiquity-os/database) and following the instructions.

### Plugin-Kernel Input/Output Interface

#### Input
Expand Down
Binary file modified bun.lockb
Binary file not shown.
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@cfworker/json-schema": "2.0.1",
"@octokit/auth-app": "7.1.0",
"@octokit/core": "6.1.2",
"@octokit/plugin-paginate-graphql": "^5.2.4",
"@octokit/plugin-paginate-rest": "11.3.3",
"@octokit/plugin-rest-endpoint-methods": "13.2.4",
"@octokit/plugin-retry": "7.1.1",
Expand All @@ -61,13 +62,11 @@
"@octokit/types": "^13.5.0",
"@octokit/webhooks": "13.3.0",
"@octokit/webhooks-types": "7.5.1",
"@sinclair/typebox": "0.32.35",
"@sinclair/typebox": "^0.33.17",
"@ubiquity-os/ubiquity-os-logger": "^1.3.2",
"dotenv": "16.4.5",
"hono": "4.4.13",
"openai": "^4.70.2",
"smee-client": "2.0.1",
"ts-node": "^10.9.2",
"typebox-validators": "0.3.5",
"yaml": "2.4.5"
},
Expand Down Expand Up @@ -100,8 +99,10 @@
"lint-staged": "15.2.7",
"npm-run-all": "4.1.5",
"prettier": "3.3.3",
"smee-client": "^2.0.4",
"toml": "3.0.0",
"tomlify-j0.4": "3.0.0",
"ts-node": "^10.9.2",
"tsup": "8.1.0",
"tsx": "4.16.2",
"typescript": "5.6.2",
Expand Down
1 change: 0 additions & 1 deletion revert-pr-108.txt

This file was deleted.

16 changes: 10 additions & 6 deletions src/github/handlers/help-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ export async function postHelpCommand(context: GitHubContext<"issue_comment.crea
const { plugin } = pluginElement.uses[0];
commands.push(...(await parseCommandsFromManifest(context, plugin)));
}
await context.octokit.rest.issues.createComment({
body: comments.concat(commands.sort()).join("\n"),
issue_number: context.payload.issue.number,
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
});
if (!commands.length) {
console.warn("No commands found, will not post the help command message.");
} else {
await context.octokit.rest.issues.createComment({
body: comments.concat(commands.sort()).join("\n"),
issue_number: context.payload.issue.number,
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
});
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/github/handlers/push-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ async function checkPluginConfigurations(context: GitHubContext<"push">, config:
value: JSON.stringify(plugin),
type: 0,
schema: configSchema,
errors: [],
});
} else {
const validator = new Validator(manifest.configuration, "7", false);
Expand All @@ -113,6 +114,7 @@ async function checkPluginConfigurations(context: GitHubContext<"push">, config:
value: JSON.stringify(value),
type: 0,
schema: configSchema,
errors: [],
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/github/types/plugin-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const configSchema = T.Object(
plugins: handlerSchema,
},
{
additionalProperties: false,
additionalProperties: true,
}
);

Expand Down
22 changes: 16 additions & 6 deletions src/sdk/actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
import { EmitterWebhookEventName as WebhookEventName } from "@octokit/webhooks";
import { Type as T, TAnySchema } from "@sinclair/typebox";
import { TAnySchema, Type as T } from "@sinclair/typebox";
import { Value } from "@sinclair/typebox/value";
import { LOG_LEVEL, LogLevel, LogReturn, Logs } from "@ubiquity-os/ubiquity-os-logger";
import { config } from "dotenv";
Expand Down Expand Up @@ -65,14 +65,24 @@ export async function createActionsPlugin<TConfig = unknown, TEnv = unknown, TSu

let config: TConfig;
if (pluginOptions.settingsSchema) {
config = Value.Decode(pluginOptions.settingsSchema, Value.Default(pluginOptions.settingsSchema, inputs.settings));
try {
config = Value.Decode(pluginOptions.settingsSchema, Value.Default(pluginOptions.settingsSchema, inputs.settings));
} catch (e) {
console.dir(...Value.Errors(pluginOptions.settingsSchema, inputs.settings), { depth: null });
throw e;
}
} else {
config = inputs.settings as TConfig;
}

let env: TEnv;
if (pluginOptions.envSchema) {
env = Value.Decode(pluginOptions.envSchema, Value.Default(pluginOptions.envSchema, process.env));
try {
env = Value.Decode(pluginOptions.envSchema, Value.Default(pluginOptions.envSchema, process.env));
} catch (e) {
console.dir(...Value.Errors(pluginOptions.envSchema, process.env), { depth: null });
throw e;
}
} else {
env = process.env as TEnv;
}
Expand Down Expand Up @@ -107,12 +117,12 @@ export async function createActionsPlugin<TConfig = unknown, TEnv = unknown, TSu
}

if (pluginOptions.postCommentOnError && loggerError) {
await postComment(context, loggerError);
await postErrorComment(context, loggerError);
}
}
}

async function postComment(context: Context, error: LogReturn) {
async function postErrorComment(context: Context, error: LogReturn) {
if ("issue" in context.payload && context.payload.repository?.owner?.login) {
await context.octokit.rest.issues.createComment({
owner: context.payload.repository.owner.login,
Expand All @@ -121,7 +131,7 @@ async function postComment(context: Context, error: LogReturn) {
body: `${error.logMessage.diff}\n<!--\n${getGithubWorkflowRunUrl()}\n${sanitizeMetadata(error.metadata)}\n-->`,
});
} else {
context.logger.info("Cannot post comment because issue is not found in the payload");
context.logger.info("Cannot post error comment because issue is not found in the payload");
}
}

Expand Down
48 changes: 48 additions & 0 deletions src/sdk/comment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Context } from "./context";
import { LogReturn } from "@ubiquity-os/ubiquity-os-logger";
import { sanitizeMetadata } from "./util";

const HEADER_NAME = "Ubiquity";

/**
* Posts a comment on a GitHub issue if the issue exists in the context payload, embedding structured metadata to it.
*/
export async function postComment(context: Context, message: LogReturn) {
if ("issue" in context.payload && context.payload.repository?.owner?.login) {
const metadata = createStructuredMetadata(message.metadata?.name, message);
await context.octokit.rest.issues.createComment({
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
issue_number: context.payload.issue.number,
body: [message.logMessage.diff, metadata].join("\n"),
});
} else {
context.logger.info("Cannot post comment because issue is not found in the payload");
}
}

function createStructuredMetadata(className: string | undefined, logReturn: LogReturn) {
const logMessage = logReturn.logMessage;
const metadata = logReturn.metadata;

const jsonPretty = sanitizeMetadata(metadata);
const stack = logReturn.metadata?.stack;
const stackLine = (Array.isArray(stack) ? stack.join("\n") : stack)?.split("\n")[2] ?? "";
const caller = stackLine.match(/at (\S+)/)?.[1] ?? "";
const ubiquityMetadataHeader = `<!-- ${HEADER_NAME} - ${className} - ${caller} - ${metadata?.revision}`;

let metadataSerialized: string;
const metadataSerializedVisible = ["```json", jsonPretty, "```"].join("\n");
const metadataSerializedHidden = [ubiquityMetadataHeader, jsonPretty, "-->"].join("\n");

if (logMessage?.type === "fatal") {
// if the log message is fatal, then we want to show the metadata
metadataSerialized = [metadataSerializedVisible, metadataSerializedHidden].join("\n");
} else {
// otherwise we want to hide it
metadataSerialized = metadataSerializedHidden;
}

// Add carriage returns to avoid any formatting issue
return `\n${metadataSerialized}\n`;
}
14 changes: 7 additions & 7 deletions src/sdk/constants.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export { DEV_CONFIG_FULL_PATH, CONFIG_FULL_PATH, CONFIG_ORG_REPO } from "../github/utils/config";
export const KERNEL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo1AYSyrXTEjMj2USno6i
5dv9Da386RI/zGypmkWa1KrIspE/Yd8RPaaEVAwt7p6+YeGcOQVLruuk11fJxff1
xB+KGbk1+kIdQ7s70B7yVRZuIM/k5aGfPpeerm0wjt4dKcYTRrl/OjLOMRrZ3vCX
E96v6eHEOpZIJ9VnjzGA0xymc+kBuEmZKabuK16S9a7I+CkZC8unqXWi15Chlyw8
EmbquwSmXI8VJ4teUjsF/H1MhJK3WTfsdr8bDsooRTMVKVBL8jONpGPzJZtr39zY
dkRj2Je2kag9b3FMxskv1npNSrPVcSc5lGNYlnZnfxIAnCknOC118JjitlrpT6wd
8wIDAQAB
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs96DOU+JqM8SyNXOB6u3
uBKIFiyrcST/LZTYN6y7LeJlyCuGPqSDrWCfjU9Ph5PLf9TWiNmeM8DGaOpwEFC7
U3NRxOSglo4plnQ5zRwIHHXvxyK400sQP2oISXymISuBQWjEIqkC9DybQrKwNzf+
I0JHWPqmwMIw26UvVOtXGOOWBqTkk+N2+/9f8eDIJP5QQVwwszc8s1rXOsLMlVIf
wShw7GO4E2jyK8TSJKpyjV8eb1JJMDwFhPiRrtZfQJUtDf2mV/67shQww61BH2Y/
Plnalo58kWIbkqZoq1yJrL5sFb73osM5+vADTXVn79bkvea7W19nSkdMiarYt4Hq
JQIDAQAB
-----END PUBLIC KEY-----
`;
export const KERNEL_APP_ID = 975031;
Expand Down
2 changes: 2 additions & 0 deletions src/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { createPlugin } from "./server";
export { createActionsPlugin } from "./actions";
export { postComment } from "./comment";
export type { Context } from "./context";
export * from "./constants";
export type { Manifest } from "../types/manifest";
3 changes: 2 additions & 1 deletion src/sdk/octokit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { paginateRest } from "@octokit/plugin-paginate-rest";
import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
import { retry } from "@octokit/plugin-retry";
import { throttling } from "@octokit/plugin-throttling";
import { paginateGraphQL } from "@octokit/plugin-paginate-graphql";

const defaultOptions = {
throttle: {
Expand All @@ -22,6 +23,6 @@ const defaultOptions = {
},
};

export const customOctokit = Octokit.plugin(throttling, retry, paginateRest, restEndpointMethods).defaults((instanceOptions: object) => {
export const customOctokit = Octokit.plugin(throttling, retry, paginateRest, restEndpointMethods, paginateGraphQL).defaults((instanceOptions: object) => {
return Object.assign({}, defaultOptions, instanceOptions);
});
36 changes: 20 additions & 16 deletions src/sdk/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { KERNEL_PUBLIC_KEY } from "./constants";
import { Context } from "./context";
import { customOctokit } from "./octokit";
import { verifySignature } from "./signature";
import { sanitizeMetadata } from "./util";
import { env as honoEnv } from "hono/adapter";
import { postComment } from "./comment";
import { Type as T } from "@sinclair/typebox";

interface Options {
Expand Down Expand Up @@ -63,18 +64,34 @@ export function createPlugin<TConfig = unknown, TEnv = unknown, TSupportedEvents
throw new HTTPException(400, { message: "Invalid signature" });
}

const inputSchemaErrors = [...Value.Errors(inputSchema, body)];
if (inputSchemaErrors.length) {
console.dir(inputSchemaErrors, { depth: null });
throw new HTTPException(400, { message: "Invalid body" });
}
const inputs = Value.Decode(inputSchema, body);

let config: TConfig;
if (pluginOptions.settingsSchema) {
config = Value.Decode(pluginOptions.settingsSchema, Value.Default(pluginOptions.settingsSchema, inputs.settings));
try {
config = Value.Decode(pluginOptions.settingsSchema, Value.Default(pluginOptions.settingsSchema, inputs.settings));
} catch (e) {
console.dir(...Value.Errors(pluginOptions.settingsSchema, inputs.settings), { depth: null });
throw e;
}
} else {
config = inputs.settings as TConfig;
}

let env: TEnv;
const honoEnvironment = honoEnv(ctx);
if (pluginOptions.envSchema) {
env = Value.Decode(pluginOptions.envSchema, Value.Default(pluginOptions.envSchema, ctx.env));
try {
env = Value.Decode(pluginOptions.envSchema, Value.Default(pluginOptions.envSchema, honoEnvironment));
} catch (e) {
console.dir(...Value.Errors(pluginOptions.envSchema, honoEnvironment), { depth: null });
throw e;
}
} else {
env = ctx.env as TEnv;
}
Expand Down Expand Up @@ -114,16 +131,3 @@ export function createPlugin<TConfig = unknown, TEnv = unknown, TSupportedEvents

return app;
}

async function postComment(context: Context, error: LogReturn) {
if ("issue" in context.payload && context.payload.repository?.owner?.login) {
await context.octokit.rest.issues.createComment({
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
issue_number: context.payload.issue.number,
body: `${error.logMessage.diff}\n<!--\n${sanitizeMetadata(error.metadata)}\n-->`,
});
} else {
context.logger.info("Cannot post comment because issue is not found in the payload");
}
}
55 changes: 55 additions & 0 deletions tests/commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,59 @@ describe("Event related tests", () => {
],
]);
});

it("Should not post the help menu when /help command if there is no available command", async () => {
const issues = {
createComment(params?: RestEndpointMethodTypes["issues"]["createComment"]["parameters"]) {
return params;
},
};
const spy = jest.spyOn(issues, "createComment");
const getContent = jest.fn((params?: RestEndpointMethodTypes["repos"]["getContent"]["parameters"]) => {
if (params?.path === CONFIG_FULL_PATH) {
return {
data: `
plugins:
- name: "Some Action plugin"
uses:
- id: plugin-B
plugin: ubiquity-os/plugin-b
`,
};
} else if (params?.path === "manifest.json") {
return {
data: {
content: btoa(
JSON.stringify({
name: "plugin",
})
),
},
};
} else {
throw new Error("Not found");
}
});
const issueCommentCreated = (await import("../src/github/handlers/issue-comment-created")).default;
await issueCommentCreated({
id: "",
key: "issue_comment.created",
octokit: {
rest: {
issues,
repos: {
getContent: getContent,
},
},
},
eventHandler: eventHandler,
payload: {
...payload,
comment: {
body: "/help",
},
} as unknown as GitHubContext<"issue_comment.created">["payload"],
} as unknown as GitHubContext);
expect(spy).not.toBeCalled();
});
});
6 changes: 4 additions & 2 deletions tests/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,13 @@ describe("SDK worker tests", () => {
body: `\`\`\`diff
! test error
\`\`\`
<!--
<!-- Ubiquity - undefined - - undefined
{
"caller": "error"
}
-->`,
-->
`,
});
});
it("Should accept correct request", async () => {
Expand Down

0 comments on commit 6d24748

Please sign in to comment.