UNPKG

probot

Version:

A framework for building GitHub Apps to automate and improve your workflow

118 lines (117 loc) • 4.55 kB
import fs from "node:fs"; import path from "node:path"; import { npxImport } from "npx-import-light"; import yaml from "yaml"; import { ProbotOctokit } from "./octokit/probot-octokit.js"; import { loadPackageJson } from "./helpers/load-package-json.js"; import { updateEnv } from "./helpers/update-env.js"; function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); } export class ManifestCreation { #updateEnv; #env; constructor(options = { updateEnv }) { this.#env = options.env || process.env; this.#updateEnv = options.updateEnv || ((values) => updateEnv(values, { env: this.#env })); } get pkg() { return loadPackageJson(); } async createWebhookChannel({ SmeeClient: SmeeClientParam, log = console, } = {}) { let SmeeClient; try { SmeeClient = SmeeClientParam || (await npxImport("smee-client@5.0.0", { onlyPackageRunner: true, })).SmeeClient; } catch { log.warn("SmeeClient is not available"); return void 0; } try { const WEBHOOK_PROXY_URL = await SmeeClient.createChannel(); this.#updateEnv({ WEBHOOK_PROXY_URL, }); return WEBHOOK_PROXY_URL; } catch { log.warn("Unable to connect to smee.io, try restarting your server."); return void 0; } } getManifest(options) { let manifest = {}; const { pkg, baseUrl, readFileSync = fs.readFileSync } = options; try { const file = readFileSync(path.join(process.cwd(), "app.yml"), "utf8"); const parsed = yaml.parse(file); if (isRecord(parsed)) { const parsedManifest = {}; if (typeof parsed.name === "string") parsedManifest.name = parsed.name; if (typeof parsed.url === "string") parsedManifest.url = parsed.url; if (typeof parsed.description === "string") { parsedManifest.description = parsed.description; } if (typeof parsed.public === "boolean") { parsedManifest.public = parsed.public; } manifest = parsedManifest; } } catch (error) { // App config does not exist, which is ok. if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) { throw error; } } const generatedManifest = JSON.stringify({ description: manifest.description || pkg.description, hook_attributes: { url: this.#env.WEBHOOK_PROXY_URL || `${baseUrl}/`, }, name: this.#env.PROJECT_DOMAIN || manifest.name || pkg.name, public: typeof manifest.public === "boolean" ? manifest.public : true, redirect_url: `${baseUrl}/probot/setup`, // TODO: add setup url // setup_url:`${baseUrl}/probot/success`, url: manifest.url || pkg.homepage || pkg.repository, version: "v1", ...manifest, }); return generatedManifest; } async createAppFromCode(code, probotOptions) { const octokit = new ProbotOctokit(probotOptions); const options = { ...probotOptions, code, mediaType: { previews: ["fury"], // needed for GHES 2.20 and older }, ...(this.#env.GHE_HOST && { baseUrl: `${this.#env.GHE_PROTOCOL || "https"}://${this.#env.GHE_HOST}/api/v3`, }), }; const response = await octokit.request("POST /app-manifests/:code/conversions", options); const { id, client_id, client_secret, webhook_secret, pem } = response.data; this.#updateEnv({ APP_ID: id.toString(), PRIVATE_KEY: `"${pem}"`, WEBHOOK_SECRET: webhook_secret, GITHUB_CLIENT_ID: client_id, GITHUB_CLIENT_SECRET: client_secret, }); return response.data.html_url; } get createAppUrl() { const githubHost = this.#env.GHE_HOST || `github.com`; return `${this.#env.GHE_PROTOCOL || "https"}://${githubHost}${this.#env.GH_ORG ? `/organizations/${this.#env.GH_ORG}` : ""}/settings/apps/new`; } }