From ddcf71225226bc0929d5c6d609b13ff0489e5b94 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 14 Aug 2021 22:28:17 +0200 Subject: Revamped backend error handling & improved imports in tests --- packages/server/src/git/blob.ts | 4 +- packages/server/src/git/branch.ts | 8 +-- packages/server/src/git/commit.ts | 10 ++-- packages/server/src/git/diff.ts | 4 +- packages/server/src/git/error.ts | 75 ------------------------- packages/server/src/git/error/index.ts | 60 ++++++++++++++++++++ packages/server/src/git/error/types.ts | 39 +++++++++++++ packages/server/src/git/misc.ts | 6 +- packages/server/src/git/repository.ts | 8 +-- packages/server/src/git/tag.ts | 6 +- packages/server/src/git/tree.ts | 6 +- packages/server/src/routes/api/v1/index.ts | 6 +- packages/server/src/routes/api/v1/repo/index.ts | 22 ++++---- packages/server/src/routes/repo.ts | 10 ++-- 14 files changed, 144 insertions(+), 120 deletions(-) delete mode 100644 packages/server/src/git/error.ts create mode 100644 packages/server/src/git/error/index.ts create mode 100644 packages/server/src/git/error/types.ts (limited to 'packages') diff --git a/packages/server/src/git/blob.ts b/packages/server/src/git/blob.ts index 5d1d892..ad88ca5 100644 --- a/packages/server/src/git/blob.ts +++ b/packages/server/src/git/blob.ts @@ -1,4 +1,4 @@ -import { BlobError, createError } from "./error"; +import { createError, ErrorWhere, IsNotError } from "./error"; import { Tree } from "./tree"; import { BlobTreeEntry } from "./tree_entry"; @@ -37,7 +37,7 @@ export class Blob { const entry = await tree.find(path); if(!(entry instanceof BlobTreeEntry)) { - throw(createError(BlobError, 500, "Not a blob")); + throw(createError(ErrorWhere.Blob, IsNotError, "tree entry", "a blob")); } return new Blob(entry); diff --git a/packages/server/src/git/branch.ts b/packages/server/src/git/branch.ts index 1dbb690..dacabda 100644 --- a/packages/server/src/git/branch.ts +++ b/packages/server/src/git/branch.ts @@ -2,7 +2,7 @@ import { CommitSummary } from "./commit"; import { Reference } from "./reference"; import { Repository } from "./repository"; import { Repository as NodeGitRepository } from "nodegit"; -import { BranchError, createError } from "./error"; +import { createError, ErrorWhere, FailedError, NotFoundError, UnknownError } from "./error"; /** * A representation of a branch @@ -17,7 +17,7 @@ export class Branch extends Reference { */ public async latestCommit(): Promise { const latest_commit = this._owner.ng_repository.getBranchCommit(this._ng_reference).catch(() => { - throw(createError(BranchError, 500, "Failed to get the latest commit")); + throw(createError(ErrorWhere.Branch, FailedError, "get the latest commit")); }); return { @@ -37,9 +37,9 @@ export class Branch extends Reference { public static async lookup(owner: Repository, branch: string): Promise { const reference = await owner.ng_repository.getBranch(branch).catch(err => { if(err.errno === -3) { - throw(createError(BranchError, 404, "Branch not found!")); + throw(createError(ErrorWhere.Branch, NotFoundError, "branch")); } - throw(createError(BranchError, 500, "Something went wrong.")); + throw(createError(ErrorWhere.Branch, UnknownError)); }); return new Branch(owner, reference); } diff --git a/packages/server/src/git/commit.ts b/packages/server/src/git/commit.ts index 32b5869..d5d8eab 100644 --- a/packages/server/src/git/commit.ts +++ b/packages/server/src/git/commit.ts @@ -7,7 +7,7 @@ import { createMessage, readKey, readSignature, verify } from "openpgp"; import { promisify } from "util"; import { exec } from "child_process"; import { findAsync } from "./misc"; -import { CommitError, createError } from "./error"; +import { ErrorWhere, createError, CommitNotSignedError, FailedError } from "./error"; const pExec = promisify(exec); @@ -46,7 +46,7 @@ export class CommitAuthor implements Author { */ public async fingerprint(): Promise { const basic_signature = await this._ng_commit.getSignature().catch(() => { - throw(createError(CommitError, 500, "Commit isn't signed!")); + throw(createError(ErrorWhere.Commit, CommitNotSignedError)); }); const message = await createMessage({ text: basic_signature.signedData }); @@ -54,7 +54,7 @@ export class CommitAuthor implements Author { const pub_keys_list = await pExec("gpg --list-public-keys"); if(pub_keys_list.stderr) { - throw(createError(CommitError, 500, "Failed to get public keys from gpg!")); + throw(createError(ErrorWhere.Commit, FailedError, "get public keys from gpg!")); } const pub_keys = pub_keys_list.stdout @@ -79,7 +79,7 @@ export class CommitAuthor implements Author { const key_export = await pExec(`gpg --armor --export ${fingerprint}`); if(key_export.stderr) { - throw(createError(CommitError, 500, "Failed to export a public key from gpg!")); + throw(createError(ErrorWhere.Commit, FailedError, "export a public key from gpg!")); } const signature = await readSignature({ armoredSignature: basic_signature.signature }); @@ -97,7 +97,7 @@ export class CommitAuthor implements Author { }); if(!pub_key) { - throw(createError(CommitError, 500, "Failed to find a public key matching the commit signature!")); + throw(createError(ErrorWhere.Commit, FailedError, "find a public key matching the commit signature!")); } return pub_key diff --git a/packages/server/src/git/diff.ts b/packages/server/src/git/diff.ts index 3d69183..d084e5d 100644 --- a/packages/server/src/git/diff.ts +++ b/packages/server/src/git/diff.ts @@ -1,5 +1,5 @@ import { Diff as NodeGitDiff } from "nodegit"; -import { createError, DiffError } from "./error"; +import { createError, ErrorWhere, NotFoundError } from "./error"; import { Patch } from "./patch"; type PatchHeaderData = { @@ -75,7 +75,7 @@ export class Diff { const patch = (await this.ng_diff.patches())[index]; if(!patch) { - throw(createError(DiffError, 500, "Patch not found")); + throw(createError(ErrorWhere.Diff, NotFoundError, "Patch")); } return new Patch(this, (await this.ng_diff.patches())[index], index); diff --git a/packages/server/src/git/error.ts b/packages/server/src/git/error.ts deleted file mode 100644 index b89b994..0000000 --- a/packages/server/src/git/error.ts +++ /dev/null @@ -1,75 +0,0 @@ -export abstract class BaseError implements Error { - code: number; - name: string; - message: string; - stack?: string | undefined; - - constructor(code: number, message: string) { - this.name = "Githermit Error"; - - this.code = code; - this.message = message; - } -} - -export class RepositoryError extends BaseError { - constructor(code: number, message: string) { - super(code, "A repository error has occured: " + message); - } -} - -export class BranchError extends BaseError { - constructor(code: number, message: string) { - super(code, "A branch error has occured: " + message); - } -} - -export class TagError extends BaseError { - constructor(code: number, message: string) { - super(code, "A tag error has occured: " + message); - } -} - -export class TreeError extends BaseError { - constructor(code: number, message: string) { - super(code, "A tree error has occured: " + message); - } -} - -export class BlobError extends BaseError { - constructor(code: number, message: string) { - super(code, "A blob error has occured: " + message); - } -} - -export class MiscError extends BaseError { - constructor(code: number, message: string) { - super(code, "A misc error has occured: " + message); - } -} - -export class DiffError extends BaseError { - constructor(code: number, message: string) { - super(code, "A diff error has occured: " + message); - } -} - -export class CommitError extends BaseError { - constructor(code: number, message: string) { - super(code, "A commit error has occured: " + message); - } -} - -type ErrorConstructorType = new (code: number, message: string) => T; - -/** - * An error factory - * - * @param ErrorConstructor - The constructor for what error to create - * @param code - A HTTP code - * @param message - A error message - * @returns An instance of a error - */ -export function createError(ErrorConstructor: ErrorConstructorType, code: number, message: string): E { - return new ErrorConstructor(code, message); -} \ No newline at end of file diff --git a/packages/server/src/git/error/index.ts b/packages/server/src/git/error/index.ts new file mode 100644 index 0000000..b8994d3 --- /dev/null +++ b/packages/server/src/git/error/index.ts @@ -0,0 +1,60 @@ +import { ErrorType } from "./types"; + +export * from "./types"; + +export class ServerError extends Error { + code: number; + + constructor(where: string, error_type: { code: number, message: string }) { + super(`A ${where} error has occured: ${error_type.message}`); + + this.name = "Server Error"; + this.code = error_type.code; + } +} + +export enum ErrorWhere { + Repository = "repository", + Tree = "tree", + Tag = "tag", + Branch = "branch", + Commit = "commit", + Diff = "diff", + Misc = "misc", + Blob = "blob" +} + +/** + * A error factory + * + * @param where - Where the error has occured + * @param err_type - What type of error it is + * @param args - Parameters for the error type + * + * @returns A server error + * + * @example Example usage: + * import { ErrorType, NotFoundError, createError } from "./error"; + * + * throw(createError(ErrorType.Repository, NotFoundError, "chili sauce")); + */ +export function createError ErrorType>(where: ErrorWhere, ErrType: T, ...args: ConstructorParameters): ServerError; + +/** + * A error factory + * + * @param where - Where the error has occured + * @param err_type - What type of error it is + * + * @returns A server error + * + * @example Example usage: + * import { ErrorType, UnknownError, createError } from "./error"; + * + * throw(createError(ErrorType.Repository, UnknownError)); + */ +export function createError ErrorType>(where: ErrorWhere, ErrType: T): ServerError; + +export function createError ErrorType>(where: ErrorWhere, ErrType: T, ...args: ConstructorParameters): ServerError { + return new ServerError(where, new ErrType(...args)); +} \ No newline at end of file diff --git a/packages/server/src/git/error/types.ts b/packages/server/src/git/error/types.ts new file mode 100644 index 0000000..b8f2de7 --- /dev/null +++ b/packages/server/src/git/error/types.ts @@ -0,0 +1,39 @@ +export abstract class ErrorType { + code: number; + message: string; + + constructor(code: number, message: string) { + this.code = code; + this.message = message; + } +} + +export class UnknownError extends ErrorType { + constructor() { + super(500, "Unknown error!"); + } +} + +export class NotFoundError extends ErrorType { + constructor(target: string) { + super(404, `${target} not found!`); + } +} + +export class FailedError extends ErrorType { + constructor(attempt: string) { + super(500, `Failed to ${attempt}!`); + } +} + +export class IsNotError extends ErrorType { + constructor(target: string, not: string) { + super(500, `${target} is not a ${not}!`); + } +} + +export class CommitNotSignedError extends ErrorType { + constructor() { + super(500, "Commit isn't signed!"); + } +} \ No newline at end of file diff --git a/packages/server/src/git/misc.ts b/packages/server/src/git/misc.ts index 1fda304..43c7a70 100644 --- a/packages/server/src/git/misc.ts +++ b/packages/server/src/git/misc.ts @@ -1,5 +1,5 @@ import { readFile, readdir } from "fs"; -import { createError, MiscError } from "./error"; +import { createError, ErrorWhere, FailedError } from "./error"; /** * Asynchronously find an item in an array that matches the requirements set by the callback @@ -25,7 +25,7 @@ export function getFile(git_dir: string, repository: string, file: string): Prom return new Promise((resolve, reject) => { readFile(`${git_dir}/${repository}/${file}`, (err, content) => { if(err) { - reject(createError(MiscError, 500, "Failed to open repository file " + file)); + reject(createError(ErrorWhere.Misc, FailedError, `open repository file '${file}'`)); return; } @@ -44,7 +44,7 @@ export function getDirectory(directory: string): Promise { return new Promise((resolve, reject) => { readdir(directory, (err, dir_content) => { if(err) { - reject(createError(MiscError, 500, "Failed to open directory " + directory)); + reject(createError(ErrorWhere.Misc, FailedError, `open directory '${directory}'`)); return; } diff --git a/packages/server/src/git/repository.ts b/packages/server/src/git/repository.ts index 63ede23..9e83281 100644 --- a/packages/server/src/git/repository.ts +++ b/packages/server/src/git/repository.ts @@ -7,7 +7,7 @@ import { Commit } from "./commit"; import { FastifyReply } from "fastify"; import { Tag } from "./tag"; import { Tree } from "./tree"; -import { createError, RepositoryError } from "./error"; +import { createError, ErrorWhere, NotFoundError, UnknownError } from "./error"; /** * Returns the full name of a git repository @@ -162,15 +162,15 @@ export class Repository { public static async open(git_dir: string, repository: string, branch?: string): Promise { let ng_repository = await NodeGitRepository.openBare(`${git_dir}/${getFullRepositoryName(repository)}`).catch((err: WeirdError) => { if(err.errno === -3) { - throw(createError(RepositoryError, 404, "Repository not found")); + throw(createError(ErrorWhere.Repository, NotFoundError, "repository")); } - throw(createError(RepositoryError, 500, "Unknown error")); + throw(createError(ErrorWhere.Repository, UnknownError)); }); if(branch) { if(!await Branch.lookupExists(ng_repository, branch)) { - throw(createError(RepositoryError, 404, "Branch not found!")); + throw(createError(ErrorWhere.Repository, NotFoundError, "branch")); } } diff --git a/packages/server/src/git/tag.ts b/packages/server/src/git/tag.ts index b792516..6c61a65 100644 --- a/packages/server/src/git/tag.ts +++ b/packages/server/src/git/tag.ts @@ -5,7 +5,7 @@ import { Reference } from "./reference"; import { Repository } from "./repository"; import { createGzip } from "zlib"; import { pipeline } from "stream"; -import { createError, TagError } from "./error"; +import { createError, ErrorWhere, FailedError, NotFoundError } from "./error"; import { Author } from "../../../api/src"; import { promisify } from "util"; @@ -88,10 +88,10 @@ export class Tag extends Reference { public static async lookup(owner: Repository, tag: string): Promise { const reference = await owner.ng_repository.getReference(tag).catch(err => { if(err.errno === -3) { - throw(createError(TagError, 404, "Tag not found")); + throw(createError(ErrorWhere.Tag, NotFoundError, "Tag")); } - throw(createError(TagError, 404, "Failed to get tag")); + throw(createError(ErrorWhere.Tag, FailedError, "get tag")); }); return new Tag(owner, reference); diff --git a/packages/server/src/git/tree.ts b/packages/server/src/git/tree.ts index 7936e5d..4b6d329 100644 --- a/packages/server/src/git/tree.ts +++ b/packages/server/src/git/tree.ts @@ -1,7 +1,7 @@ import { Tree as NodeGitTree } from "nodegit"; import { Repository } from "./repository"; import { BaseTreeEntry, BlobTreeEntry, createTreeEntry, TreeEntry } from "./tree_entry"; -import { createError, TreeError } from "./error"; +import { createError, ErrorWhere, FailedError, NotFoundError } from "./error"; import { pack, Pack } from "tar-stream"; import { Commit } from "./commit"; @@ -42,9 +42,9 @@ export class Tree { public async find(path: string): Promise { const entry = await this._ng_tree.getEntry(path).catch(err => { if(err.errno === -3) { - throw(createError(TreeError, 404, `Path '${path}' not found`)); + throw(createError(ErrorWhere.Tree, NotFoundError, `Path '${path}'`)); } - throw(createError(TreeError, 500, "Failed to get tree path")); + throw(createError(ErrorWhere.Tree, FailedError, "get tree path")); }); return createTreeEntry(this._owner, entry); diff --git a/packages/server/src/routes/api/v1/index.ts b/packages/server/src/routes/api/v1/index.ts index 1adb3cb..fa7d8ab 100644 --- a/packages/server/src/routes/api/v1/index.ts +++ b/packages/server/src/routes/api/v1/index.ts @@ -4,7 +4,7 @@ import { Route } from "../../../types/fastify"; import repo from "./repo"; import { verifyRepoName } from "../util"; import { Info as APIInfo, RepositorySummary as APIRepositorySummary, Repository as APIRepository } from "api"; -import { BaseError } from "../../../git/error"; +import { ServerError } from "../../../git/error"; function setHandlers(fastify: FastifyInstance): void { fastify.setErrorHandler((err, req, reply) => { @@ -49,9 +49,9 @@ function reposEndpoints(fastify: FastifyInstance, opts: FastifyPluginOptions, do return; } - const repository: Repository | BaseError = await Repository.open(opts.config.settings.git_dir, req.params.repo).catch(err => err); + const repository = await Repository.open(opts.config.settings.git_dir, req.params.repo).catch((err: ServerError) => err); - if(repository instanceof BaseError) { + if(repository instanceof ServerError) { reply.code(repository.code).send({ error: repository.message }); return; } diff --git a/packages/server/src/routes/api/v1/repo/index.ts b/packages/server/src/routes/api/v1/repo/index.ts index bcd2e5c..059a9d4 100644 --- a/packages/server/src/routes/api/v1/repo/index.ts +++ b/packages/server/src/routes/api/v1/repo/index.ts @@ -8,7 +8,7 @@ import branches from "./branches"; import log from "./log"; import { verifyRepoName } from "../../util"; import { Tree as APITree, Tag as APITag, TreeEntry as APITreeEntry } from "api"; -import { BaseError } from "../../../../git/error"; +import { ServerError } from "../../../../git/error"; import { commitMap } from "./map"; declare module "fastify" { @@ -19,9 +19,9 @@ declare module "fastify" { function addHooks(fastify: FastifyInstance, opts: FastifyPluginOptions): void { fastify.addHook("preHandler", async(req: CoolFastifyRequest, reply) => { - const repository = await Repository.open(opts.config.settings.git_dir, req.params.repo, req.query.branch).catch((err: BaseError) => err); + const repository = await Repository.open(opts.config.settings.git_dir, req.params.repo, req.query.branch).catch((err: ServerError) => err); - if(repository instanceof BaseError) { + if(repository instanceof ServerError) { reply.code(repository.code).send({ error: repository.message }); return; } @@ -67,9 +67,9 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/tree", handler: async(req, reply) => { - const tree = await req.repository.tree().catch((err: BaseError) => err); + const tree = await req.repository.tree().catch((err: ServerError) => err); - if(tree instanceof BaseError) { + if(tree instanceof ServerError) { reply.code(tree.code).send({ error: tree.message }); return; } @@ -81,9 +81,9 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do let data: APITree; if(tree_path) { - const tree_path_entry = await tree.find(tree_path).catch((err: BaseError) => err); + const tree_path_entry = await tree.find(tree_path).catch((err: ServerError) => err); - if(tree_path_entry instanceof BaseError) { + if(tree_path_entry instanceof ServerError) { reply.code(tree_path_entry.code).send({ error: tree_path_entry.message }); return; } @@ -104,9 +104,9 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/tree/history", handler: async(req, reply) => { - const tree = await req.repository.tree().catch((err: BaseError) => err); + const tree = await req.repository.tree().catch((err: ServerError) => err); - if(tree instanceof BaseError) { + if(tree instanceof ServerError) { reply.code(tree.code).send({ error: tree.message }); return; } @@ -118,9 +118,9 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do const tree_path = req.query.path; - const tree_entry = await tree.find(tree_path).catch((err: BaseError) => err); + const tree_entry = await tree.find(tree_path).catch((err: ServerError) => err); - if(tree_entry instanceof BaseError) { + if(tree_entry instanceof ServerError) { reply.code(tree_entry.code).send({ error: tree_entry.message }); return; } diff --git a/packages/server/src/routes/repo.ts b/packages/server/src/routes/repo.ts index 43d89d2..32ac9c4 100644 --- a/packages/server/src/routes/repo.ts +++ b/packages/server/src/routes/repo.ts @@ -3,7 +3,7 @@ import { CoolFastifyRequest, Route } from "../types/fastify"; import { Tag } from "../git/tag"; import { FastifyInstance, FastifyPluginOptions } from "fastify"; import { verifyRepoName } from "../routes/api/util"; -import { BaseError } from "../git/error"; +import { ServerError } from "../git/error"; export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, done: (err?: Error) => void): void { fastify.addHook("onRequest", async(req: CoolFastifyRequest, reply) => { @@ -62,16 +62,16 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/refs/tags/:tag", handler: async(req, reply) => { - const repository = await Repository.open(opts.config.settings.git_dir, req.params.repo).catch((err: BaseError) => err); + const repository = await Repository.open(opts.config.settings.git_dir, req.params.repo).catch((err: ServerError) => err); - if(repository instanceof BaseError) { + if(repository instanceof ServerError) { reply.code(repository.code).send(repository.message); return; } - const tag = await Tag.lookup(repository, req.params.tag).catch((err: BaseError) => err); + const tag = await Tag.lookup(repository, req.params.tag).catch((err: ServerError) => err); - if(tag instanceof BaseError) { + if(tag instanceof ServerError) { reply.code(tag.code).send(tag.message); return; } -- cgit v1.2.3-18-g5258