diff --git a/README.md b/README.md index 11eb0da..fdcb0dc 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ The `createActionsPlugin` function allows users to create plugins that will be a The `createPlugin` function enables users to create a plugin that will run on Cloudflare Workers environment. +### `postComment` + +The `postComment` function enables users to easily post a comment to an issue, a pull-request, or a pull request review thread. + ## Getting Started To set up the project locally, `bun` is the preferred package manager. diff --git a/bun.lockb b/bun.lockb index 148525e..dda0025 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 809df9c..671016a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ubiquity-os/plugin-sdk", - "version": "0.0.0", + "version": "1.1.1", "description": "SDK for plugin support.", "author": "Ubiquity DAO", "license": "MIT", @@ -110,7 +110,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-check-file": "^2.8.0", "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-sonarjs": "^2.0.4", + "eslint-plugin-sonarjs": "^3.0.1", "husky": "^9.0.11", "jest": "^29.7.0", "jest-junit": "^16.0.0", @@ -129,7 +129,7 @@ }, "lint-staged": { "*.ts": [ - "bun prettier --write", + "prettier --write", "eslint --fix" ], "src/**.{ts,json}": [ diff --git a/src/actions.ts b/src/actions.ts index 8772c61..3ffd894 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -5,13 +5,14 @@ import { Type as T } from "@sinclair/typebox"; import { Value } from "@sinclair/typebox/value"; import { LogReturn, Logs } from "@ubiquity-os/ubiquity-os-logger"; import { config } from "dotenv"; +import { postComment } from "./comment"; import { Context } from "./context"; import { customOctokit } from "./octokit"; import { verifySignature } from "./signature"; import { commandCallSchema } from "./types/command"; import { HandlerReturn } from "./types/sdk"; import { jsonType } from "./types/util"; -import { getPluginOptions, Options, sanitizeMetadata } from "./util"; +import { getPluginOptions, Options } from "./util"; config(); @@ -120,28 +121,11 @@ export async function createActionsPlugin`, - }); - } else { - context.logger.info("Cannot post error comment because issue is not found in the payload"); - } -} - -function getGithubWorkflowRunUrl() { - return `${github.context.payload.repository?.html_url}/actions/runs/${github.context.runId}`; -} - async function returnDataToKernel(repoToken: string, stateId: string, output: HandlerReturn) { const octokit = new customOctokit({ auth: repoToken }); await octokit.rest.repos.createDispatchEvent({ diff --git a/src/comment.ts b/src/comment.ts index cf87399..170c884 100644 --- a/src/comment.ts +++ b/src/comment.ts @@ -1,35 +1,76 @@ +import { LogReturn, Metadata } from "@ubiquity-os/ubiquity-os-logger"; import { Context } from "./context"; -import { LogReturn } from "@ubiquity-os/ubiquity-os-logger"; +import { PluginRuntimeInfo } from "./helpers/runtime-info"; import { sanitizeMetadata } from "./util"; -const HEADER_NAME = "Ubiquity"; +const HEADER_NAME = "UbiquityOS"; /** * 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); +export async function postComment(context: Context, message: LogReturn | Error, raw = false) { + let issueNumber; + + if ("issue" in context.payload) { + issueNumber = context.payload.issue.number; + } else if ("pull_request" in context.payload) { + issueNumber = context.payload.pull_request.number; + } else if ("discussion" in context.payload) { + issueNumber = context.payload.discussion.number; + } else { + context.logger.info("Cannot post comment because issue is not found in the payload."); + return; + } + + if ("repository" in context.payload && context.payload.repository?.owner?.login) { + const body = await createStructuredMetadataWithMessage(context, message, raw); 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"), + issue_number: issueNumber, + body: body, }); } else { - context.logger.info("Cannot post comment because issue is not found in the payload"); + context.logger.info("Cannot post comment because repository is not found in the payload.", { payload: context.payload }); } } -function createStructuredMetadata(className: string | undefined, logReturn: LogReturn) { - const logMessage = logReturn.logMessage; - const metadata = logReturn.metadata; +async function createStructuredMetadataWithMessage(context: Context, message: LogReturn | Error, raw = false) { + let logMessage; + let callingFnName; + let instigatorName; + let metadata: Metadata; + if (message instanceof Error) { + metadata = { + message: message.message, + name: message.name, + stack: message.stack, + }; + callingFnName = message.stack?.split("\n")[2]?.match(/at (\S+)/)?.[1] ?? "anonymous"; + logMessage = context.logger.error(message.message).logMessage; + } else if (message.metadata) { + metadata = { + message: message.metadata.message, + stack: message.metadata.stack || message.metadata.error?.stack, + caller: message.metadata.caller || message.metadata.error?.stack?.split("\n")[2]?.match(/at (\S+)/)?.[1], + }; + logMessage = message.logMessage; + callingFnName = metadata.caller; + } else { + metadata = { ...message }; + } 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 = `