diff --git a/.gitignore b/.gitignore index 061bbf8f90..eeca89753b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ /obj/** /*.sln* /*.njsproj* +/*.tgz diff --git a/lib/misc-action.ts b/lib/misc-action.ts new file mode 100644 index 0000000000..4d37244af1 --- /dev/null +++ b/lib/misc-action.ts @@ -0,0 +1,82 @@ +import { CIHelper } from "./ci-helper"; +import { isDirectory } from "./fs-util"; +import { getConfig } from "./gitgitgadget-config"; +import { getVar } from "./gitgitgadget"; +import { IConfig, loadConfig, setConfig } from "./project-config"; +import path from "path"; + +export interface actionInterface { + action: string; + repositoryDir: string; + configRepositoryDir: string; + config: string; + repoOwner: string; + repoName: string; + skipUpdate?: string | undefined; +} + +/** + * Handle various gitgitgadget requests. + * + * @param parms + */ + +export async function handleAction(parms: actionInterface): Promise { + const config: IConfig = parms.config ? setConfig(await getExternalConfig(parms.config)) : getConfig(); + + // Update with current values + config.repo.name = parms.repoName; + config.repo.owner = parms.repoOwner; + setConfig(config); + + lintConfig(config); + + if (!(await isDirectory(parms.repositoryDir))) { + throw new Error(`git WorkDir '${parms.repositoryDir}' not found.`); + } + + const ci = new CIHelper(parms.repositoryDir, parms.skipUpdate ? true : false, parms.configRepositoryDir); + + if (parms.action === "update-open-prs") { + const result = await ci.updateOpenPrs(); + console.log(`Updated notes: ${result}`); + } else if (parms.action === "update-commit-mappings") { + const result = await ci.updateCommitMappings(); + console.log(`Updated notes: ${result}`); + } else if (parms.action === "handle-open-prs") { + const options = await ci.getGitGitGadgetOptions(); + if (!options.openPRs) { + throw new Error("No open PRs?"); + } + const result = await ci.handleOpenPRs(); + console.log(`Updated notes: ${result}`); + } else if (parms.action === "handle-new-mails") { + const mailArchiveGitDir = await getVar("loreGitDir", undefined); + + if (!mailArchiveGitDir) { + throw new Error("Need a lore.kernel/git worktree."); + } + + await ci.handleNewMails(mailArchiveGitDir); + } else { + throw new Error(`Unknown action '${parms.action}'.`); + } +} + +async function getExternalConfig(file: string): Promise { + return await loadConfig(path.resolve(file)); +} + +function lintConfig(config: IConfig): void { + if (!config.hasOwnProperty("project")) { + throw new Error(`User configurations must have a 'project:'. Not found in ${path}`); + } + + if (!config.repo.owner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { + throw new Error(`Invalid 'owner' ${config.repo.owner} in ${path}`); + } + + if (!config.repo.baseOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { + throw new Error(`Invalid 'baseOwner' ${config.repo.baseOwner} in ${path}`); + } +} diff --git a/lib/pull-action.ts b/lib/pull-action.ts new file mode 100644 index 0000000000..bd62b3dac8 --- /dev/null +++ b/lib/pull-action.ts @@ -0,0 +1,74 @@ +import { CIHelper } from "./ci-helper"; +import { isDirectory } from "./fs-util"; +import { getConfig } from "./gitgitgadget-config"; +import { IConfig, loadConfig, setConfig } from "./project-config"; +import path from "path"; + +export interface PRUpdateInterface { + action: string; + repositoryDir: string; + configRepositoryDir: string; + config: string; + repoOwner: string; + repoName: string; + repoBaseowner: string; + pullRequestNumber: string; + commentId?: string | undefined; + skipUpdate?: string | undefined; +} + +/** + * Handle an update to a pull request. It may be a create or sync of changes or a comment. + * + * @param parms + */ + +export async function handlePRUpdate(parms: PRUpdateInterface): Promise { + const config: IConfig = parms.config ? setConfig(await getExternalConfig(parms.config)) : getConfig(); + + // Update with current values + config.repo.name = parms.repoName; + config.repo.owner = parms.repoOwner; + config.repo.baseOwner = parms.repoBaseowner; + setConfig(config); + + lintConfig(config); + + if (!(await isDirectory(parms.repositoryDir))) { + throw new Error(`git WorkDir '${parms.repositoryDir}' not found.`); + } + + const ci = new CIHelper(parms.repositoryDir, parms.skipUpdate ? true : false, parms.configRepositoryDir); + + if (parms.action === "comment") { + if (parms.commentId) { + const commentId = parseInt(parms.commentId, 10); + await ci.handleComment(parms.repoOwner, commentId); + } else { + throw new Error(`Action '${parms.action}' requires a comment-id.`); + } + } else if (parms.action === "push") { + const pullRequestNumber = parseInt(parms.pullRequestNumber, 10); + await ci.handlePush(parms.repoOwner, pullRequestNumber); + } else { + throw new Error(`Unknown action '${parms.action}'.`); + } +} + +async function getExternalConfig(file: string): Promise { + return await loadConfig(path.resolve(file)); +} + +function lintConfig(config: IConfig): void { + if (!config.hasOwnProperty("project")) { + throw new Error(`User configurations must have a 'project:'. Not found in ${path}`); + } + + if (!config.repo.owner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { + throw new Error(`Invalid 'owner' ${config.repo.owner} in ${path}`); + } + + if (!config.repo.baseOwner.match(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i)) { + throw new Error(`Invalid 'baseOwner' ${config.repo.baseOwner} in ${path}`); + } +} diff --git a/package.json b/package.json index 0c41a5c85a..aa15630124 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "url": "https://github.com/gitgitgadget/gitgitgadget/issues" }, "homepage": "https://gitgitgadget.github.io/", + "files": [ + "lib/*.ts" + ], "jest": { "moduleFileExtensions": [ "ts",