diff --git a/bun.lockb b/bun.lockb index 26de14f..98c3ed0 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index faa914c..a4c7cd0 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "typings": "dist/index.d.ts", "exports": { ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js", - "import": "./dist/index.mjs" + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.mjs" } }, "files": [ @@ -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", @@ -61,7 +62,7 @@ "@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", diff --git a/revert-pr-108.txt b/revert-pr-108.txt deleted file mode 100644 index 72e6611..0000000 --- a/revert-pr-108.txt +++ /dev/null @@ -1 +0,0 @@ -This file was created to revert PR #108 \ No newline at end of file diff --git a/src/github/handlers/push-event.ts b/src/github/handlers/push-event.ts index 2cf8f77..7ceea65 100644 --- a/src/github/handlers/push-event.ts +++ b/src/github/handlers/push-event.ts @@ -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); @@ -113,6 +114,7 @@ async function checkPluginConfigurations(context: GitHubContext<"push">, config: value: JSON.stringify(value), type: 0, schema: configSchema, + errors: [], }); } } diff --git a/src/github/types/plugin-configuration.ts b/src/github/types/plugin-configuration.ts index 02316d7..0bd2b2d 100644 --- a/src/github/types/plugin-configuration.ts +++ b/src/github/types/plugin-configuration.ts @@ -80,7 +80,7 @@ export const configSchema = T.Object( plugins: handlerSchema, }, { - additionalProperties: false, + additionalProperties: true, } ); diff --git a/src/sdk/actions.ts b/src/sdk/actions.ts index b8af3b8..fdd53b9 100644 --- a/src/sdk/actions.ts +++ b/src/sdk/actions.ts @@ -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"; @@ -58,14 +58,24 @@ export async function createActionsPlugin`, }); } 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"); } } diff --git a/src/sdk/comment.ts b/src/sdk/comment.ts new file mode 100644 index 0000000..cf87399 --- /dev/null +++ b/src/sdk/comment.ts @@ -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 = `"].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`; +} diff --git a/src/sdk/index.ts b/src/sdk/index.ts index 4339ddf..4e05ca0 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -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"; diff --git a/src/sdk/octokit.ts b/src/sdk/octokit.ts index 31ed90a..0b7f8c5 100644 --- a/src/sdk/octokit.ts +++ b/src/sdk/octokit.ts @@ -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: { @@ -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); }); diff --git a/src/sdk/server.ts b/src/sdk/server.ts index 9c60e6e..bf069cf 100644 --- a/src/sdk/server.ts +++ b/src/sdk/server.ts @@ -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 { @@ -54,7 +55,13 @@ export function createPlugin`, - }); - } else { - context.logger.info("Cannot post comment because issue is not found in the payload"); - } -} diff --git a/tests/sdk.test.ts b/tests/sdk.test.ts index 6657231..43e7357 100644 --- a/tests/sdk.test.ts +++ b/tests/sdk.test.ts @@ -146,11 +146,13 @@ describe("SDK worker tests", () => { body: `\`\`\`diff ! test error \`\`\` -`, +--> +`, }); }); it("Should accept correct request", async () => {