diff --git a/.github/workflows/push-github-actions.yml b/.github/workflows/push-github-actions.yml index d7084499f5..cf5d224358 100644 --- a/.github/workflows/push-github-actions.yml +++ b/.github/workflows/push-github-actions.yml @@ -66,7 +66,7 @@ jobs: # Now, add the generated files git add -A dist/ && # Remove the rest - git rm -r -- \* ':(exclude)dist/' ':(exclude)*/action.yml' ':(exclude)*/index.js' && + git rm -r -- \* ':(exclude)dist/' ':(exclude)*/action.yml' ':(exclude)*/index.js' ':(exclude)*/post.js' && # Now make that fake merge commit tree=$(git write-tree) && diff --git a/.vscode/settings.json b/.vscode/settings.json index e51062ffc9..8bcacc2e87 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -83,6 +83,7 @@ "tbdiff", "Thái", "Truthy", + "typia", "unportable", "vger", "VSTS", diff --git a/check-run/action.yml b/check-run/action.yml new file mode 100644 index 0000000000..610c7a9319 --- /dev/null +++ b/check-run/action.yml @@ -0,0 +1,53 @@ +name: 'Create or update a Check Run' +description: 'Mirrors a workflow run to a Check Run of a Pull Request in a different repository' +author: 'Johannes Schindelin' +inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing + pr-repo-token: + description: 'The access token to work on the repository that holds PRs and state' + required: true + upstream-repo-token: + description: 'The access token to work on PRs in the upstream repository' + required: false + test-repo-token: + description: 'The access token to work on PRs in the test repository' + required: false + pr-url: + description: 'The URL of the Pull Request (or Pull Request comment)' + required: false + check-run-id: + description: 'The Check Run to update (if empty, a new one will be created)' + default: '' + name: + description: 'The name of the CheckRun (required if check-run-id is empty)' + default: '' + title: + description: 'The Check Run title (required when creating a new one)' + default: '' + summary: + description: 'The Check Run summary (required when creating a new one)' + default: '' + text: + description: 'The Check Run text (required when creating a new one)' + default: '' + details-url: + description: 'The details URL of the Check Run (required when creating a new one)' + default: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}' + conclusion: + description: 'If set, the Check Run will be marked as completed' + default: '' + job-status: + description: 'Needed at the end of the job' + default: ${{ job.status }} +outputs: + check-run-id: + description: 'The ID of the created or updated Check Run' +runs: + using: 'node20' + main: './index.js' + post: './post.js' +branding: + icon: 'git-commit' + color: 'orange' \ No newline at end of file diff --git a/check-run/index.js b/check-run/index.js new file mode 100644 index 0000000000..5706cf3c1f --- /dev/null +++ b/check-run/index.js @@ -0,0 +1,13 @@ +async function run() { + const { CIHelper } = await import("../dist/index.js") + + try { + const ci = new CIHelper() + ci.setupGitHubAction({ createOrUpdateCheckRun: true }) + } catch (e) { + console.error(e) + process.exitCode = 1 + } +} + +run() diff --git a/check-run/post.js b/check-run/post.js new file mode 100644 index 0000000000..3682f8fca8 --- /dev/null +++ b/check-run/post.js @@ -0,0 +1,13 @@ +async function run() { + const { CIHelper } = await import("../dist/index.js") + + try { + const ci = new CIHelper() + ci.setupGitHubAction({ createOrUpdateCheckRun: "post" }) + } catch (e) { + console.error(e) + process.exitCode = 1 + } +} + +run() diff --git a/handle-new-mails/action.yml b/handle-new-mails/action.yml index 23dc2676cb..7f35716860 100644 --- a/handle-new-mails/action.yml +++ b/handle-new-mails/action.yml @@ -2,6 +2,9 @@ name: 'Handle new mails' description: 'Processes new mails on the Git mailing list' author: 'Johannes Schindelin' inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing pr-repo-token: description: 'The access token to work on the repository that holds PRs and state' required: true diff --git a/handle-pr-comment/action.yml b/handle-pr-comment/action.yml index 564bd7dfd1..c9b65bc961 100644 --- a/handle-pr-comment/action.yml +++ b/handle-pr-comment/action.yml @@ -2,6 +2,9 @@ name: 'Handle PR Comment' description: 'Handles slash commands such as /submit and /preview' author: 'Johannes Schindelin' inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing pr-repo-token: description: 'The access token to work on the repository that holds PRs and state' required: true diff --git a/handle-pr-comment/index.js b/handle-pr-comment/index.js index d330752030..0667313504 100644 --- a/handle-pr-comment/index.js +++ b/handle-pr-comment/index.js @@ -2,10 +2,10 @@ async function run() { const { CIHelper } = await import("../dist/index.js") const ci = new CIHelper() - const { owner, commentId } = ci.parsePRCommentURLInput() + const { owner, comment_id } = ci.parsePRCommentURLInput() await ci.setupGitHubAction() - await ci.handleComment(owner, commentId) + await ci.handleComment(owner, comment_id) } run() diff --git a/handle-pr-push/action.yml b/handle-pr-push/action.yml index e5b74c8e0c..15eab3879f 100644 --- a/handle-pr-push/action.yml +++ b/handle-pr-push/action.yml @@ -2,6 +2,9 @@ name: 'Handle PR Pushes' description: 'Handles when a PR was pushed' author: 'Johannes Schindelin' inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing pr-repo-token: description: 'The access token to work on the repository that holds PRs and state' required: true diff --git a/handle-pr-push/index.js b/handle-pr-push/index.js index 91f594e976..446181eb12 100644 --- a/handle-pr-push/index.js +++ b/handle-pr-push/index.js @@ -2,10 +2,10 @@ async function run() { const { CIHelper } = await import("../dist/index.js") const ci = new CIHelper() - const { owner, prNumber } = ci.parsePRURLInput() + const { owner, pull_number } = ci.parsePRURLInput() await ci.setupGitHubAction() - await ci.handlePush(owner, prNumber) + await ci.handlePush(owner, pull_number) } run() diff --git a/lib/ci-helper.ts b/lib/ci-helper.ts index 43b763fe5c..34ae748171 100644 --- a/lib/ci-helper.ts +++ b/lib/ci-helper.ts @@ -1,6 +1,7 @@ import * as core from "@actions/core"; import * as fs from "fs"; import * as os from "os"; +import typia from "typia"; import * as util from "util"; import { spawnSync } from "child_process"; import addressparser from "nodemailer/lib/addressparser/index.js"; @@ -10,14 +11,27 @@ import { commitExists, git, emptyTreeName, revParse } from "./git.js"; import { GitNotes } from "./git-notes.js"; import { GitGitGadget, IGitGitGadgetOptions } from "./gitgitgadget.js"; import { getConfig } from "./gitgitgadget-config.js"; -import { GitHubGlue, IGitHubUser, IPRComment, IPRCommit, IPullRequestInfo, RequestError } from "./github-glue.js"; +import { + ConclusionType, + GitHubGlue, + IGitHubUser, + IPRComment, + IPRCommit, + IPullRequestInfo, + RequestError, +} from "./github-glue.js"; import { toPrettyJSON } from "./json-util.js"; import { MailArchiveGitHelper } from "./mail-archive-helper.js"; import { MailCommitMapping } from "./mail-commit-mapping.js"; import { IMailMetadata } from "./mail-metadata.js"; import { IPatchSeriesMetadata } from "./patch-series-metadata.js"; import { IConfig, getExternalConfig, setConfig } from "./project-config.js"; -import { getPullRequestKeyFromURL, pullRequestKey } from "./pullRequestKey.js"; +import { + getPullRequestCommentKeyFromURL, + getPullRequestKeyFromURL, + getPullRequestOrCommentKeyFromURL, + pullRequestKey, +} from "./pullRequestKey.js"; import { ISMTPOptions } from "./send-mail.js"; import { fileURLToPath } from "url"; @@ -53,8 +67,24 @@ export class CIHelper { return configFile ? await getExternalConfig(configFile) : getConfig(); } + public static validateConfig = typia.createValidate(); + + protected static getConfigAsGitHubActionInput(): IConfig | undefined { + if (process.env.GITHUB_ACTIONS !== "true") return undefined; + const json = core.getInput("config"); + if (!json) return undefined; + const config = JSON.parse(json) as IConfig | undefined; + const result = CIHelper.validateConfig(config); + if (result.success) return config; + throw new Error( + `Invalid config:\n- ${result.errors + .map((e) => `${e.path} (value: ${e.value}, expected: ${e.expected}): ${e.description}`) + .join("\n- ")}`, + ); + } + public constructor(workDir: string = "pr-repo.git", config?: IConfig, skipUpdate?: boolean, gggConfigDir = ".") { - this.config = config !== undefined ? setConfig(config) : getConfig(); + this.config = config !== undefined ? setConfig(config) : CIHelper.getConfigAsGitHubActionInput() || getConfig(); this.gggConfigDir = gggConfigDir; this.workDir = workDir; this.notes = new GitNotes(workDir); @@ -72,24 +102,8 @@ export class CIHelper { needsMailingListMirror?: boolean; needsUpstreamBranches?: boolean; needsMailToCommitNotes?: boolean; + createOrUpdateCheckRun?: boolean | "post"; }): Promise { - // help dugite realize where `git` is... - const gitExecutable = os.type() === "Windows_NT" ? "git.exe" : "git"; - const stripSuffix = `bin${path.sep}${gitExecutable}`; - for (const gitPath of (process.env.PATH || "/") - .split(path.delimiter) - .map((p) => path.normalize(`${p}${path.sep}${gitExecutable}`)) - // eslint-disable-next-line security/detect-non-literal-fs-filename - .filter((p) => p.endsWith(`${path.sep}${stripSuffix}`) && fs.existsSync(p))) { - process.env.LOCAL_GIT_DIRECTORY = gitPath.substring(0, gitPath.length - stripSuffix.length); - // need to override GIT_EXEC_PATH, so that Dugite can find the `git-remote-https` executable, - // see https://github.com/desktop/dugite/blob/v2.7.1/lib/git-environment.ts#L44-L64 - // Also: We cannot use `await git(["--exec-path"]);` because that would use Dugite, which would - // override `GIT_EXEC_PATH` and then `git --exec-path` would report _that_... - process.env.GIT_EXEC_PATH = spawnSync(gitPath, ["--exec-path"]).stdout.toString("utf-8").trimEnd(); - break; - } - // configure the Git committer information process.env.GIT_CONFIG_PARAMETERS = [ process.env.GIT_CONFIG_PARAMETERS, @@ -101,7 +115,7 @@ export class CIHelper { // get the access tokens via the inputs of the GitHub Action this.setAccessToken(this.config.repo.owner, core.getInput("pr-repo-token")); - this.setAccessToken(this.config.repo.baseOwner, core.getInput("upstream-repo-token")); + this.setAccessToken(this.config.repo.upstreamOwner, core.getInput("upstream-repo-token")); if (this.config.repo.testOwner) { this.setAccessToken(this.config.repo.testOwner, core.getInput("test-repo-token")); } @@ -121,6 +135,27 @@ export class CIHelper { // Ignore, for now } + if (setupOptions?.createOrUpdateCheckRun) { + return await this.createOrUpdateCheckRun(setupOptions.createOrUpdateCheckRun === "post"); + } + + // help dugite realize where `git` is... + const gitExecutable = os.type() === "Windows_NT" ? "git.exe" : "git"; + const stripSuffix = `bin${path.sep}${gitExecutable}`; + for (const gitPath of (process.env.PATH || "/") + .split(path.delimiter) + .map((p) => path.normalize(`${p}${path.sep}${gitExecutable}`)) + // eslint-disable-next-line security/detect-non-literal-fs-filename + .filter((p) => p.endsWith(`${path.sep}${stripSuffix}`) && fs.existsSync(p))) { + process.env.LOCAL_GIT_DIRECTORY = gitPath.substring(0, gitPath.length - stripSuffix.length); + // need to override GIT_EXEC_PATH, so that Dugite can find the `git-remote-https` executable, + // see https://github.com/desktop/dugite/blob/v2.7.1/lib/git-environment.ts#L44-L64 + // Also: We cannot use `await git(["--exec-path"]);` because that would use Dugite, which would + // override `GIT_EXEC_PATH` and then `git --exec-path` would report _that_... + process.env.GIT_EXEC_PATH = spawnSync(gitPath, ["--exec-path"]).stdout.toString("utf-8").trimEnd(); + break; + } + // eslint-disable-next-line security/detect-non-literal-fs-filename if (!fs.existsSync(this.workDir)) await git(["init", "--bare", "--initial-branch", "unused", this.workDir]); for (const [key, value] of [ @@ -128,7 +163,7 @@ export class CIHelper { ["remote.origin.url", `https://github.com/${this.config.repo.owner}/${this.config.repo.name}`], ["remote.origin.promisor", "true"], ["remote.origin.partialCloneFilter", "blob:none"], - ["remote.upstream.url", `https://github.com/${this.config.repo.baseOwner}/${this.config.repo.name}`], + ["remote.upstream.url", `https://github.com/${this.config.repo.upstreamOwner}/${this.config.repo.name}`], ["remote.upstream.promisor", "true"], ["remote.upstream.partialCloneFilter", "blob:none"], ]) { @@ -175,7 +210,7 @@ export class CIHelper { console.time("get open PR head commits"); const openPRCommits = ( await Promise.all( - this.config.repo.owners.map(async (repositoryOwner) => { + this.config.app.installedOn.map(async (repositoryOwner) => { return await this.github.getOpenPRs(repositoryOwner); }), ) @@ -252,24 +287,79 @@ export class CIHelper { } } - public parsePRCommentURLInput(): { owner: string; repo: string; prNumber: number; commentId: number } { - const prCommentUrl = core.getInput("pr-comment-url"); - const [, owner, repo, prNumber, commentId] = - prCommentUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)#issuecomment-(\d+)$/) || []; - if (!this.config.repo.owners.includes(owner) || repo !== this.config.repo.name) { - throw new Error(`Invalid PR comment URL: ${prCommentUrl}`); + protected async createOrUpdateCheckRun(runPost: boolean): Promise { + type CheckRunParameters = { + owner: string; + repo: string; + pull_number: number; + check_run_id?: number; + name: string; + output?: { + title: string; + summary: string; + text?: string; + }; + details_url?: string; + conclusion?: ConclusionType; + job_status?: ConclusionType; + }; + const params = JSON.parse(core.getState("check-run") || "{}") as CheckRunParameters; + + const validateCheckRunParameters = () => { + const result = typia.createValidate()(params); + if (!result.success) { + throw new Error( + `Invalid check-run state:\n- ${result.errors + .map((e) => `${e.path} (value: ${e.value}, expected: ${e.expected}): ${e.description}`) + .join("\n- ")}`, + ); + } + }; + if (Object.keys(params).length) validateCheckRunParameters(); + + ["pr-url", "check-run-id", "name", "title", "summary", "text", "details-url", "conclusion", "job-status"] + .map((name) => [name.replaceAll("-", "_"), core.getInput(name)] as const) + .forEach(([key, value]) => { + if (!value) return; + if (key === "pr_url") Object.assign(params, getPullRequestOrCommentKeyFromURL(value)); + else if (key === "check_run_id") params.check_run_id = Number.parseInt(value, 10); + else if (key === "title" || key === "summary" || key === "text") { + if (!params.output) Object.assign(params, { output: {} }); + (params.output as { [key: string]: string })[key] = value; + } else (params as unknown as { [key: string]: string })[key] = value; + }); + validateCheckRunParameters(); + + if (runPost) { + if (!params.check_run_id) { + core.info("No Check Run ID found in state; doing nothing"); + return; + } + if (!params.conclusion) { + Object.assign(params, { conclusion: params.job_status }); + validateCheckRunParameters(); + } + } + + if (params.check_run_id === undefined) { + ({ id: params.check_run_id } = await this.github.createCheckRun(params)); + core.setOutput("check-run-id", params.check_run_id); + } else { + await this.github.updateCheckRun({ + ...params, + // needed to pacify TypeScript's concerns about the ID being potentially undefined + check_run_id: params.check_run_id, + }); } - return { owner, repo, prNumber: parseInt(prNumber, 10), commentId: parseInt(commentId, 10) }; + core.exportVariable("STATE_check-run", JSON.stringify(params)); } - public parsePRURLInput(): { owner: string; repo: string; prNumber: number } { - const prUrl = core.getInput("pr-url"); + public parsePRCommentURLInput(): { owner: string; repo: string; pull_number: number; comment_id: number } { + return getPullRequestCommentKeyFromURL(core.getInput("pr-comment-url")); + } - const [, owner, repo, prNumber] = prUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)$/) || []; - if (!this.config.repo.owners.includes(owner) || repo !== this.config.repo.name) { - throw new Error(`Invalid PR URL: ${prUrl}`); - } - return { owner, repo, prNumber: parseInt(prNumber, 10) }; + public parsePRURLInput(): { owner: string; repo: string; pull_number: number } { + return getPullRequestKeyFromURL(core.getInput("pr-url")); } public setAccessToken(repositoryOwner: string, token: string): void { @@ -411,7 +501,7 @@ export class CIHelper { mailMeta.originalCommit, upstreamCommit, this.config.repo.owner, - this.config.repo.baseOwner, + this.config.repo.upstreamOwner, ); } @@ -654,7 +744,7 @@ export class CIHelper { // Add comment on GitHub const comment = `This patch series was integrated into ${branch} via https://github.com/${ - this.config.repo.baseOwner + this.config.repo.upstreamOwner }/${this.config.repo.name}/commit/${mergeCommit}.`; const url = await this.github.addPRComment(prKey, comment); console.log(`Added comment ${url.id} about ${branch}: ${url.url}`); @@ -892,7 +982,7 @@ export class CIHelper { await addComment( `Submitted as [${ metadata?.coverLetterMessageId - }](https://${this.config.mailrepo.host}/${this.config.mailrepo.name}/${ + }](${this.config.mailrepo.url.replace(/\/+$/, "")}/${ metadata?.coverLetterMessageId })\n\nTo fetch this version into \`FETCH_HEAD\`:${ code @@ -1020,7 +1110,7 @@ export class CIHelper { if (result) { const results = commits.map((commit: IPRCommit) => { - const linter = new LintCommit(commit); + const linter = new LintCommit(commit, this.config.lint.commitLintOptions); return linter.lint(); }); @@ -1137,7 +1227,7 @@ export class CIHelper { const handledPRs = new Set(); const handledMessageIDs = new Set(); - for (const repositoryOwner of this.config.repo.owners) { + for (const repositoryOwner of this.config.app.installedOn) { const pullRequests = await this.github.getOpenPRs(repositoryOwner); for (const pr of pullRequests) { @@ -1195,7 +1285,7 @@ export class CIHelper { private async getPRInfo(prKey: pullRequestKey): Promise { const pr = await this.github.getPRInfo(prKey); - if (!this.config.repo.owners.includes(pr.baseOwner) || pr.baseRepo !== this.config.repo.name) { + if (!this.config.app.installedOn.includes(pr.baseOwner) || pr.baseRepo !== this.config.repo.name) { throw new Error(`Unsupported repository: ${pr.pullRequestURL}`); } diff --git a/lib/commit-lint.ts b/lib/commit-lint.ts index 3eab1f22cf..7e046d7538 100644 --- a/lib/commit-lint.ts +++ b/lib/commit-lint.ts @@ -5,7 +5,7 @@ export interface ILintError { message: string; } -export interface ILintOptions { +export interface ILintCommitConfig { maxColumns?: number | undefined; // max line length } @@ -19,7 +19,7 @@ export class LintCommit { private messages: string[] = []; private maxColumns = 76; - public constructor(patch: IPRCommit, options?: ILintOptions) { + public constructor(patch: IPRCommit, options?: ILintCommitConfig) { this.blocked = false; this.lines = patch.message.split("\n"); this.patch = patch; diff --git a/lib/gitgitgadget-config.ts b/lib/gitgitgadget-config.ts index 47ba1eb16d..5144094aba 100644 --- a/lib/gitgitgadget-config.ts +++ b/lib/gitgitgadget-config.ts @@ -4,9 +4,8 @@ const defaultConfig: IConfig = { repo: { name: "git", owner: "gitgitgadget", - baseOwner: "git", + upstreamOwner: "git", testOwner: "dscho", - owners: ["gitgitgadget", "git", "dscho"], branches: ["maint", "seen"], closingBranches: ["maint", "master"], trackingBranches: ["maint", "seen", "master", "next"], @@ -27,6 +26,8 @@ const defaultConfig: IConfig = { mail: { author: "GitGitGadget", sender: "GitGitGadget", + smtpUser: "gitgitgadget@gmail.com", + smtpHost: "smtp.gmail.com", }, app: { appID: 12836, @@ -34,6 +35,7 @@ const defaultConfig: IConfig = { name: "gitgitgadget", displayName: "GitGitGadget", altname: "gitgitgadget-git", + installedOn: ["gitgitgadget", "git", "dscho"], }, lint: { maxCommitsIgnore: ["https://github.com/gitgitgadget/git/pull/923"], @@ -42,6 +44,18 @@ const defaultConfig: IConfig = { user: { allowUserAsLogin: false, }, + syncUpstreamBranches: [ + { + sourceRepo: "gitster/git", + targetRepo: "gitgitgadget/git", + sourceRefRegex: "^refs/heads/(maint-\\d|[a-z][a-z]/)", + }, + { + sourceRepo: "j6t/git-gui", + targetRepo: "gitgitgadget/git", + targetRefNamespace: "git-gui/", + }, + ], }; export default defaultConfig; diff --git a/lib/github-glue.ts b/lib/github-glue.ts index a20e0af38c..ca7900e139 100644 --- a/lib/github-glue.ts +++ b/lib/github-glue.ts @@ -51,6 +51,17 @@ export interface IGitHubUser { type: string; } +export type ConclusionType = + | "action_required" + | "cancelled" + | "failure" + | "neutral" + | "success" + | "skipped" + | "stale" + | "timed_out" + | undefined; + export class GitHubGlue { public workDir: string; protected client: Octokit = new Octokit(); // add { log: console } to debug @@ -477,6 +488,60 @@ export class GitHubGlue { this.tokens.set(repositoryOwner, token); } + public async createCheckRun(options: { + owner: string; + repo: string; + pull_number: number; + name: string; + output?: { + title: string; + summary: string; + text?: string; + }; + details_url?: string; + conclusion?: ConclusionType; + }): Promise<{ id: number }> { + if (process.env.GITGITGADGET_DRY_RUN) { + console.log(`Would create Check Run with options ${JSON.stringify(options, null, 2)}`); + return { id: -1 }; // debug mode does not actually do anything + } + + await this.ensureAuthenticated(options.owner); + const prInfo = await this.getPRInfo(options); + const { data } = await this.client.checks.create({ + ...options, + head_sha: prInfo.headCommit, + status: options.conclusion ? "completed" : "in_progress", + }); + return data; + } + + public async updateCheckRun(options: { + owner: string; + repo: string; + check_run_id: number; + output?: { + title?: string; + summary: string; + text?: string; + }; + detailsURL?: string; + conclusion?: ConclusionType; + }): Promise<{ id: number }> { + if (process.env.GITGITGADGET_DRY_RUN) { + console.log(`Would create Check Run with options ${JSON.stringify(options, null, 2)}`); + return { id: -1 }; // debug mode does not actually do anything + } + + await this.ensureAuthenticated(options.owner); + const { data } = await this.client.checks.update({ + ...options, + conclusion: options.conclusion, + status: options.conclusion ? "completed" : "in_progress", + }); + return data; + } + protected async ensureAuthenticated(repositoryOwner: string): Promise { if (repositoryOwner !== this.authenticated) { let token = this.tokens.get(repositoryOwner); diff --git a/lib/project-config.ts b/lib/project-config.ts index c96a732224..3299c60e12 100644 --- a/lib/project-config.ts +++ b/lib/project-config.ts @@ -1,5 +1,6 @@ import * as fs from "fs"; import path from "path"; +import { ILintCommitConfig } from "./commit-lint.js"; export type projectInfo = { to: string; // email to send patches to @@ -8,49 +9,71 @@ export type projectInfo = { urlPrefix: string; // url to 'listserv' of mail (should it be in mailrepo?) }; +export interface IRepoConfig { + name: string; // name of the repo + owner: string; // owner of repo holding the notes (tracking data) + upstreamOwner: string; // owner of upstream ("base") repo + testOwner?: string; // owner of the test repo (if any) + branches: string[]; // remote branches to fetch - just use trackingBranches? + closingBranches: string[]; // close if the pr is added to this branch + trackingBranches: string[]; // comment if the pr is added to this branch + maintainerBranch?: string; // branch/owner manually implementing changes + host: string; +} + +export interface IMailRepoConfig { + name: string; + owner: string; + branch: string; + host: string; + url: string; + public_inbox_epoch?: number; + mirrorURL?: string; + mirrorRef?: string; + descriptiveName: string; +} +export interface IMailConfig { + author: string; + sender: string; + smtpUser: string; + smtpHost: string; +} + +export interface IAppConfig { + appID: number; + installationID: number; + name: string; + displayName: string; // name to use in comments to identify app + installedOn: string[]; // owners of clones being monitored (PR checking) + altname: string | undefined; // is this even needed? +} + +export interface ILintConfig { + maxCommitsIgnore?: string[]; // array of pull request urls to skip check + maxCommits: number; // limit on number of commits in a pull request + commitLintOptions?: ILintCommitConfig; // options to pass to commit linter +} + +export interface IUserConfig { + allowUserAsLogin: boolean; // use GitHub login as name if name is private +} + +export interface ISyncUpstreamBranchesConfig { + sourceRepo: string; // e.g. "gitster/git" + targetRepo: string; // e.g. "gitgitgadget/git" + sourceRefRegex?: string; // e.g. "^refs/heads/(maint-\\d|[a-z][a-z]/)" + targetRefNamespace?: string; // e.g. "git-gui/" +} + export interface IConfig { - repo: { - name: string; // name of the repo - owner: string; // owner of repo holding the notes (tracking data) - baseOwner: string; // owner of upstream ("base") repo - testOwner?: string; // owner of the test repo (if any) - owners: string[]; // owners of clones being monitored (PR checking) - branches: string[]; // remote branches to fetch - just use trackingBranches? - closingBranches: string[]; // close if the pr is added to this branch - trackingBranches: string[]; // comment if the pr is added to this branch - maintainerBranch?: string; // branch/owner manually implementing changes - host: string; - }; - mailrepo: { - name: string; - owner: string; - branch: string; - host: string; - url: string; - public_inbox_epoch?: number; - mirrorURL?: string; - mirrorRef?: string; - descriptiveName: string; - }; - mail: { - author: string; - sender: string; - }; + repo: IRepoConfig; + mailrepo: IMailRepoConfig; + mail: IMailConfig; project?: projectInfo | undefined; // project-options values - app: { - appID: number; - installationID: number; - name: string; - displayName: string; // name to use in comments to identify app - altname: string | undefined; // is this even needed? - }; - lint: { - maxCommitsIgnore?: string[]; // array of pull request urls to skip check - maxCommits: number; // limit on number of commits in a pull request - }; - user: { - allowUserAsLogin: boolean; // use GitHub login as name if name is private - }; + app: IAppConfig; + lint: ILintConfig; + user: IUserConfig; + syncUpstreamBranches: ISyncUpstreamBranchesConfig[]; // branches to sync from upstream to our repo } let config: IConfig; // singleton @@ -80,8 +103,8 @@ export async function getExternalConfig(file: string): Promise { throw new Error(`Invalid 'owner' ${newConfig.repo.owner} in ${filePath}`); } - if (!newConfig.repo.baseOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { - throw new Error(`Invalid 'baseOwner' ${newConfig.repo.baseOwner} in ${filePath}`); + if (!newConfig.repo.upstreamOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { + throw new Error(`Invalid 'baseOwner' ${newConfig.repo.upstreamOwner} in ${filePath}`); } return newConfig; diff --git a/lib/pullRequestKey.ts b/lib/pullRequestKey.ts index b480cecfc6..a7b8bc3e99 100644 --- a/lib/pullRequestKey.ts +++ b/lib/pullRequestKey.ts @@ -15,11 +15,39 @@ export function getPullRequestKey(pullRequest: pullRequestKeyInfo): pullRequestK return typeof pullRequest === "string" ? getPullRequestKeyFromURL(pullRequest) : pullRequest; } -export function getPullRequestKeyFromURL(pullRequestURL: string): pullRequestKey { - const match = pullRequestURL.match(/^https:\/\/github.com\/(.*)\/(.*)\/pull\/(\d+)$/); +export type pullRequestCommentKey = pullRequestKey & { comment_id: number }; + +export function getPullRequestOrCommentKeyFromURL( + pullRequestOrCommentURL: string, +): pullRequestKey & { comment_id?: number } { + const match = pullRequestOrCommentURL.match(/^https:\/\/github.com\/(.*)\/(.*)\/pull\/(\d+)(.*)$/); if (!match) { - throw new Error(`Unrecognized PR URL: "${pullRequestURL}`); + throw new Error(`Unrecognized PR URL: "${pullRequestOrCommentURL}`); + } + const match2 = match[4]?.match(/^#issuecomment-(\d+)$/); + if (match[4] && !match2) { + throw new Error(`Unrecognized PR URL: "${pullRequestOrCommentURL}`); } + return { + owner: match[1], + repo: match[2], + pull_number: parseInt(match[3], 10), + comment_id: match2 ? parseInt(match2[1], 10) : undefined, + }; +} - return { owner: match[1], repo: match[2], pull_number: parseInt(match[3], 10) }; +export function getPullRequestKeyFromURL(pullRequestURL: string): pullRequestKey { + const { comment_id, ...prKey } = getPullRequestOrCommentKeyFromURL(pullRequestURL); + if (comment_id) { + throw new Error(`Expected PR URL, not a PR comment URL: `); + } + return prKey; +} + +export function getPullRequestCommentKeyFromURL(pullRequestURL: string): pullRequestCommentKey { + const result = getPullRequestOrCommentKeyFromURL(pullRequestURL); + if (result.comment_id === undefined) { + throw new Error(`Expected PR comment URL, not a PR URL: `); + } + return result as pullRequestCommentKey; } diff --git a/package-lock.json b/package-lock.json index 8e89fb73f3..9c0acf6d8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,8 +46,10 @@ "ts-jest": "^29.4.4", "ts-jest-resolver": "^2.0.1", "ts-node": "^10.9.2", - "typescript": "^5.9.3", - "typescript-eslint": "8.46.0" + "ts-patch": "^3.3.0", + "typescript": "~5.9.3", + "typescript-eslint": "8.46.0", + "typia": "^9.7.2" }, "engines": { "node": ">= 18.16.1" @@ -1607,6 +1609,28 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -3580,6 +3604,13 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@samchon/openapi": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@samchon/openapi/-/openapi-4.7.1.tgz", + "integrity": "sha512-+rkMlSKMt7l3KGWJVWUle1CXEm0vA8FIF2rufHl+T1gN/gGrTEhL1gDK3FHYf8Nl5XReK0r1vL6Q2QTMwQN7xQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.11.0", "license": "MIT", @@ -4253,6 +4284,13 @@ "node": ">=18.0.0" } }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@stylistic/eslint-plugin": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.4.0.tgz", @@ -5286,6 +5324,13 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/babel-jest": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", @@ -5400,12 +5445,45 @@ "node": ">=0.12.0" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", "license": "Apache-2.0" }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/bowser": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.0.tgz", @@ -5488,6 +5566,31 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "license": "BSD-3-Clause" @@ -5609,6 +5712,13 @@ "node": ">=10" } }, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "dev": true, + "license": "MIT" + }, "node_modules/chownr": { "version": "2.0.0", "license": "ISC", @@ -5637,6 +5747,42 @@ "dev": true, "license": "MIT" }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -5692,6 +5838,16 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -5735,6 +5891,23 @@ "node": ">=20" } }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -5755,6 +5928,13 @@ "dev": true, "license": "MIT" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/create-require": { "version": "1.1.1", "dev": true, @@ -5819,6 +5999,19 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -5900,6 +6093,16 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/dugite": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/dugite/-/dugite-2.7.1.tgz", @@ -6615,6 +6818,32 @@ "bser": "2.1.1" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -6878,6 +7107,47 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/global-prefix": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -6953,6 +7223,16 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -7068,6 +7348,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -7141,6 +7442,80 @@ "dev": true, "license": "ISC" }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.7", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz", + "integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/external-editor": "^1.0.0", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ipv6-normalize": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz", @@ -7205,6 +7580,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7227,6 +7612,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "2.0.5", "license": "MIT" @@ -9908,6 +10306,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/leac": { "version": "0.6.0", "license": "MIT", @@ -9987,6 +10395,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "license": "MIT" @@ -10025,6 +10440,23 @@ "version": "4.1.1", "license": "MIT" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -10225,6 +10657,13 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, "node_modules/napi-postinstall": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", @@ -10367,6 +10806,30 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-limit": { "version": "3.1.0", "dev": true, @@ -10412,6 +10875,16 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10745,6 +11218,23 @@ ], "license": "MIT" }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -10766,6 +11256,20 @@ ], "license": "MIT" }, + "node_modules/randexp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", + "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "drange": "^1.0.2", + "ret": "^0.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -10773,6 +11277,21 @@ "dev": true, "license": "MIT" }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexp-tree": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", @@ -10783,6 +11302,16 @@ "regexp-tree": "bin/regexp-tree" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -10850,6 +11379,37 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -10875,6 +11435,16 @@ "node": ">=0.8.0" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -10899,6 +11469,16 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -11098,6 +11678,16 @@ "node": ">=8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -11365,6 +11955,13 @@ "node": ">= 18.16.1" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tlds": { "version": "1.259.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz", @@ -11516,6 +12113,25 @@ } } }, + "node_modules/ts-patch": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ts-patch/-/ts-patch-3.3.0.tgz", + "integrity": "sha512-zAOzDnd5qsfEnjd9IGy1IRuvA7ygyyxxdxesbhMdutt8AHFjD8Vw8hU2rMF89HX1BKRWFYqKHrO8Q6lw0NeUZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "global-prefix": "^4.0.0", + "minimist": "^1.2.8", + "resolve": "^1.22.2", + "semver": "^7.6.3", + "strip-ansi": "^6.0.1" + }, + "bin": { + "ts-patch": "bin/ts-patch.js", + "tspc": "bin/tspc.js" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -11604,6 +12220,38 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/typia": { + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/typia/-/typia-9.7.2.tgz", + "integrity": "sha512-eLIKd0KHZtSvbsA+FYwX+Y0ZBt0BwVGz3GgODQX+6GfGL4DOzKW02LEx62oUZg6vCQX1BL5xyiPXAIdW+Hc51g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@samchon/openapi": "^4.7.1", + "@standard-schema/spec": "^1.0.0", + "commander": "^10.0.0", + "comment-json": "^4.2.3", + "inquirer": "^8.2.5", + "package-manager-detector": "^0.2.0", + "randexp": "^0.5.3" + }, + "bin": { + "typia": "lib/executable/typia.js" + }, + "peerDependencies": { + "typescript": ">=4.8.0 <5.10.0" + } + }, + "node_modules/typia/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/uc.micro": { "version": "2.0.0", "license": "MIT" @@ -11728,6 +12376,13 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/uuid": { "version": "8.3.2", "dev": true, @@ -11764,6 +12419,16 @@ "makeerror": "1.0.12" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/which": { "version": "2.0.2", "dev": true, diff --git a/package.json b/package.json index 356109dd36..7325eb6cb0 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "test:clean": "jest --clearCache && npm test", "test:config": "npm run test -- --testRegex=/tests-config/.*\\.test\\.ts", "test:watch": "jest --watch --notify --notifyMode=change --coverage", - "ci": "npm run lint && npm run test -- --ci --reporters=default --reporters=jest-junit" + "ci": "npm run lint && npm run test -- --ci --reporters=default --reporters=jest-junit", + "prepare": "ts-patch install" }, "bugs": { "url": "https://github.com/gitgitgadget/gitgitgadget/issues" @@ -70,8 +71,10 @@ "ts-jest": "^29.4.4", "ts-jest-resolver": "^2.0.1", "ts-node": "^10.9.2", - "typescript": "^5.9.3", - "typescript-eslint": "8.46.0" + "ts-patch": "^3.3.0", + "typescript": "~5.9.3", + "typescript-eslint": "8.46.0", + "typia": "^9.7.2" }, "dependencies": { "@actions/core": "^1.11.1", diff --git a/script/misc-helper.ts b/script/misc-helper.ts index 7d16254c5d..00e4319ee6 100644 --- a/script/misc-helper.ts +++ b/script/misc-helper.ts @@ -200,7 +200,7 @@ const commandOptions = commander.opts(); originalCommit, gitGitCommit, config.repo.owner, - config.repo.baseOwner, + config.repo.upstreamOwner, ); console.log(`Created check with id ${id}`); }); diff --git a/tests-config/ci-helper.test.ts b/tests-config/ci-helper.test.ts index 3ce98c5623..752de945a8 100644 --- a/tests-config/ci-helper.test.ts +++ b/tests-config/ci-helper.test.ts @@ -16,8 +16,7 @@ const testConfig: IConfig = { repo: { name: "telescope", owner: "webb", - baseOwner: "galileo", - owners: ["webb", "galileo"], + upstreamOwner: "galileo", branches: ["maint"], closingBranches: ["maint", "main"], trackingBranches: ["maint", "main", "hubble"], @@ -41,7 +40,8 @@ const testConfig: IConfig = { installationID: 195971, name: "gitgitgadget", displayName: "BigScopes", - altname: "gitgitgadget-git" + altname: "gitgitgadget-git", + installedOn: ["webb", "galileo"], }, lint: { maxCommitsIgnore: [], @@ -172,7 +172,7 @@ async function setupRepos(instance: string): await gggLocal.git([ "config", `url.${gggRemote.workDir}.insteadOf`, url ]); // pretend there are two remotes await gggLocal.git([ "config", `url.${gggRemote.workDir}.insteadOf`, - `https://github.com/${config.repo.baseOwner}/${config.repo.name}` ]); + `https://github.com/${config.repo.upstreamOwner}/${config.repo.name}` ]); // set needed config await worktree.git([ "config", "--add", "gitgitgadget.workDir", gggLocal.workDir, ]); diff --git a/tests/commit-lint.test.ts b/tests/commit-lint.test.ts index 37f3b6eb34..da6ec70b20 100644 --- a/tests/commit-lint.test.ts +++ b/tests/commit-lint.test.ts @@ -1,5 +1,5 @@ import { expect, jest, test } from "@jest/globals"; -import { ILintError, ILintOptions, LintCommit } from "../lib/commit-lint.js"; +import { ILintError, ILintCommitConfig, LintCommit } from "../lib/commit-lint.js"; import { IPRCommit } from "../lib/github-glue.js"; jest.setTimeout(180000); @@ -15,7 +15,7 @@ jest.setTimeout(180000); * @param check a function to verify the lint result * @param options extra linter options, if any */ -function lintCheck(commit: IPRCommit, check?: (error: ILintError) => void, options?: ILintOptions) { +function lintCheck(commit: IPRCommit, check?: (error: ILintError) => void, options?: ILintCommitConfig) { const linter = new LintCommit(commit, options); const lintError = linter.lint(); if (!check) { diff --git a/tsconfig.json b/tsconfig.json index 71cbfe8ffd..97bc0e57fc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -42,7 +42,7 @@ "types": [ "node" ], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ /* Source Map Options */ @@ -54,6 +54,13 @@ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + "plugins": [ + { + "transform": "typia/lib/transform" + } + ], + "skipLibCheck": true, + "strictNullChecks": true }, "include": [ "lib/**/*.ts", diff --git a/update-mail-to-commit-notes/action.yml b/update-mail-to-commit-notes/action.yml index 76e2b3b1a4..30166453c0 100644 --- a/update-mail-to-commit-notes/action.yml +++ b/update-mail-to-commit-notes/action.yml @@ -2,6 +2,9 @@ name: 'Update the mail <-> commit notes' description: 'Updates the mapping between commits and patch emails, stored in the `mail-to-commit` and `commit-to-mail` Git notes refs.' author: 'Johannes Schindelin' inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing pr-repo-token: description: 'The access token to work on the repository that holds PRs and state' required: true diff --git a/update-prs/action.yml b/update-prs/action.yml index 34dbaecf0b..f5cfd056a6 100644 --- a/update-prs/action.yml +++ b/update-prs/action.yml @@ -2,6 +2,9 @@ name: 'Update the Pull Requests' description: 'Updates the Pull Requests in response to upstream commits' author: 'Johannes Schindelin' inputs: + config: + description: 'The GitGitGadget configuration to use (see https://github.com/gitgitgadget/gitgitgadget/blob/HEAD/lib/project-config.ts)' + default: '' # sadly, ${{ vars.CONFIG }} does not work, and documentation about what contexts are permissible here is sorely missing pr-repo-token: description: 'The access token to work on the repository that holds PRs and state' required: true