diff options
-rw-r--r-- | packages/server/src/api/util.ts | 26 | ||||
-rw-r--r-- | packages/server/src/api/v1/index.ts | 15 | ||||
-rw-r--r-- | packages/server/src/api/v1/repo/branches.ts | 4 | ||||
-rw-r--r-- | packages/server/src/api/v1/repo/index.ts | 42 | ||||
-rw-r--r-- | packages/server/src/api/v1/repo/log.ts | 6 | ||||
-rw-r--r-- | packages/server/src/app.ts | 34 | ||||
-rw-r--r-- | packages/server/src/git/blob.ts | 4 | ||||
-rw-r--r-- | packages/server/src/git/branch.ts | 21 | ||||
-rw-r--r-- | packages/server/src/git/commit.ts | 6 | ||||
-rw-r--r-- | packages/server/src/git/error.ts | 49 | ||||
-rw-r--r-- | packages/server/src/git/misc.ts | 5 | ||||
-rw-r--r-- | packages/server/src/git/reference.ts | 15 | ||||
-rw-r--r-- | packages/server/src/git/repository.ts | 54 | ||||
-rw-r--r-- | packages/server/src/git/tag.ts | 12 | ||||
-rw-r--r-- | packages/server/src/git/tree.ts | 16 |
15 files changed, 210 insertions, 99 deletions
diff --git a/packages/server/src/api/util.ts b/packages/server/src/api/util.ts index e1eaa2c..e7e7657 100644 --- a/packages/server/src/api/util.ts +++ b/packages/server/src/api/util.ts @@ -26,30 +26,8 @@ export class VerificationResult { message: string | null = null; } -export function verifyRepoName(base_dir: string, repo_name: string): Promise<VerificationResult> { - return new Promise<VerificationResult>(resolve => { - console.log(repo_name); - const is_valid_repo_name = (/^[a-zA-Z0-9.\-_]+$/u).test(repo_name); - if(!is_valid_repo_name) { - resolve(new VerificationResult("INVALID", "repository")); - return; - } - - readdir(base_dir, (err, dir_content) => { - if(err) { - resolve(new VerificationResult("NOT_FOUND", "repository")); - return; - } - - const dir_content_repos = dir_content.filter(repo => repo.endsWith(".git")); - if(!dir_content_repos.includes(repo_name + ".git")) { - resolve(new VerificationResult("NOT_FOUND", "repository")); - return; - } - - resolve(new VerificationResult("SUCCESS")); - }); - }); +export function verifyRepoName(repo_name: string): boolean { + return /^[a-zA-Z0-9.\-_]+$/u.test(repo_name); } export async function verifySHA(repository: Repository, sha: string): Promise<VerificationResult> { diff --git a/packages/server/src/api/v1/index.ts b/packages/server/src/api/v1/index.ts index c6b9187..169ba3a 100644 --- a/packages/server/src/api/v1/index.ts +++ b/packages/server/src/api/v1/index.ts @@ -4,6 +4,7 @@ import { Route } from "../../fastify_types"; import repo from "./repo"; import { verifyRepoName } from "../util"; import { Info as APIInfo, RepositorySummary as APIRepositorySummary, Repository as APIRepository } from "shared_types"; +import { BaseError } from "../../git/error"; function setHandlers(fastify: FastifyInstance): void { fastify.setErrorHandler((err, req, reply) => { @@ -32,7 +33,7 @@ function reposEndpoints(fastify: FastifyInstance, opts: FastifyPluginOptions, do return <APIRepositorySummary>{ name: repository.name.short, description: repository.description, - last_updated: (await repository.latestCommit()).date + last_updated: (await repository.masterCommit()).date }; })) }); @@ -43,13 +44,17 @@ function reposEndpoints(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/repos/:repo", handler: async(req, reply) => { - const repo_verification = await verifyRepoName(opts.config.settings.base_dir, req.params.repo); - if(repo_verification.success === false && repo_verification.code) { - reply.code(repo_verification.code).send({ error: repo_verification.message }); + if(!verifyRepoName(req.params.repo)) { + reply.code(400).send({ error: "Bad request" }); return; } - const repository = await Repository.open(opts.config.settings.base_dir, req.params.repo); + const repository = await Repository.open(opts.config.settings.base_dir, req.params.repo).catch(err => err); + + if(repository instanceof BaseError) { + reply.code(repository.code).send({ error: repository.message }); + return; + } const data: APIRepository = { name: repository.name.short, diff --git a/packages/server/src/api/v1/repo/branches.ts b/packages/server/src/api/v1/repo/branches.ts index b280a4a..c01e858 100644 --- a/packages/server/src/api/v1/repo/branches.ts +++ b/packages/server/src/api/v1/repo/branches.ts @@ -8,7 +8,7 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/branches", handler: async(req, reply) => { - const branches = await (await req.repository).branches(); + const branches = await req.repository.branches(); reply.send({ data: branches.map(branch => { @@ -25,7 +25,7 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/branches/:branch", handler: async(req, reply) => { - const branch = await Branch.lookup(await req.repository, req.params.branch); + const branch = await Branch.lookup(req.repository, req.params.branch); if(!branch) { reply.code(404).send({ error: "Branch not found!" }); diff --git a/packages/server/src/api/v1/repo/index.ts b/packages/server/src/api/v1/repo/index.ts index 8fc9ac1..e33484a 100644 --- a/packages/server/src/api/v1/repo/index.ts +++ b/packages/server/src/api/v1/repo/index.ts @@ -9,26 +9,31 @@ import branches from "./branches"; import log from "./log"; import { verifyRepoName } from "../../util"; import { Tree as APITree, Tag as APITag, TreeEntry as APITreeEntry } from "shared_types"; +import { BaseError } from "../../../git/error"; +import { Tree } from "../../../git/tree"; declare module "fastify" { interface FastifyRequest { - repository: Promise<Repository>, + repository: Repository, } } function addHooks(fastify: FastifyInstance, opts: FastifyPluginOptions): void { - fastify.addHook("preHandler", (req: CoolFastifyRequest, reply, hookDone) => { - req.repository = Repository.open(opts.config.settings.base_dir, req.params.repo); + fastify.addHook("preHandler", async(req: CoolFastifyRequest, reply) => { + const repository = await Repository.open(opts.config.settings.base_dir, req.params.repo, req.query.branch).catch((err: BaseError) => err); - hookDone(); + if(repository instanceof BaseError) { + reply.code(repository.code).send({ error: repository.message }); + return; + } + + req.repository = repository; }); fastify.addHook("onRequest", async(req: CoolFastifyRequest, reply) => { - const repo_verification = await verifyRepoName(opts.config.settings.base_dir, req.params.repo); - if(repo_verification.success === false && repo_verification.code) { - reply.code(repo_verification.code).send({ error: repo_verification.message }); + if(!verifyRepoName(req.params.repo)) { + reply.code(400).send({ error: "Bad request" }); } - }); } async function treeEntryMap(entry: TreeEntry) { @@ -63,23 +68,28 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/tree", handler: async(req, reply) => { - const tree = await (await req.repository).tree(); + const tree: Tree | BaseError = await req.repository.tree().catch(err => err); + + if(tree instanceof BaseError) { + reply.code(tree.code).send({ error: tree.message }); + return; + } const tree_path = (Object.keys(req.query).length !== 0 && req.query.path) ? req.query.path : null; let data: APITree; if(tree_path) { - const tree_found = await tree.find(tree_path); + const tree_path_entry: Tree | Blob | BaseError = await tree.find(tree_path).catch(err => err); - if(!tree_found) { - reply.code(404).send({ error: "Tree path not found!" }); + if(tree_path_entry instanceof BaseError) { + reply.code(tree_path_entry.code).send({ error: tree_path_entry.message }); return; } - data = tree_found instanceof Blob - ? { type: "blob", content: await tree_found.content() } - : { type: "tree", content: await Promise.all(tree_found.entries().map(treeEntryMap)) }; + data = tree_path_entry instanceof Blob + ? { type: "blob", content: await tree_path_entry.content() } + : { type: "tree", content: await Promise.all(tree_path_entry.entries().map(treeEntryMap)) }; } else { data = { type: "tree", content: await Promise.all(tree.entries().map(treeEntryMap)) }; @@ -93,7 +103,7 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/tags", handler: async(req, reply) => { - const tags = await (await req.repository).tags(); + const tags = await req.repository.tags(); reply.send({ data: await Promise.all(tags.map(tagMap)) }); diff --git a/packages/server/src/api/v1/repo/log.ts b/packages/server/src/api/v1/repo/log.ts index 8157696..fb876b8 100644 --- a/packages/server/src/api/v1/repo/log.ts +++ b/packages/server/src/api/v1/repo/log.ts @@ -37,7 +37,7 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/log", handler: async(req, reply) => { - const commits = (await (await req.repository).commits()); + const commits = await req.repository.commits(); reply.send({ data: await Promise.all(commits.map(commitMap)) @@ -49,12 +49,12 @@ export default function(fastify: FastifyInstance, opts: FastifyPluginOptions, do method: "GET", url: "/log/:commit", handler: async(req, reply) => { - const commit_verification = await verifySHA(await req.repository, req.params.commit); + const commit_verification = await verifySHA(req.repository, req.params.commit); if(commit_verification.success === false && commit_verification.code) { reply.code(commit_verification.code).send({ error: commit_verification.message }); } - const commit = await Commit.lookup(await req.repository, req.params.commit); + const commit = await Commit.lookup(req.repository, req.params.commit); const stats = await commit.stats(); diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 7bc66b2..ae220a9 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -9,6 +9,7 @@ import fastifyStatic from "fastify-static"; import { join } from "path"; import { load } from "js-yaml"; import { verifyRepoName } from "./api/util"; +import { BaseError } from "./git/error"; type Settings = { host: string, @@ -95,9 +96,9 @@ fastify.route<Route>({ handler: async(req, reply) => { reply.header("Content-Type", "application/x-git-upload-pack-advertisement"); - const repo_verification = await verifyRepoName(settings.base_dir, req.params.repo); - if(repo_verification.success === false && repo_verification.code) { - reply.code(repo_verification.code).send(repo_verification.message); + if(!verifyRepoName(req.params.repo)) { + reply.code(400).send({ error: "Bad request" }); + return; } if(!req.query.service) { @@ -126,11 +127,9 @@ fastify.route<Route>({ method: "POST", url: "/:repo([a-zA-Z0-9\\.\\-_]+)/git-upload-pack", handler: async(req, reply) => { - const repo_verification = await verifyRepoName(settings.base_dir, req.params.repo); - - if(repo_verification.success === false && repo_verification.code) { - reply.header("Content-Type", "application/x-git-upload-pack-result"); - reply.code(repo_verification.code).send(repo_verification.message); + if(!verifyRepoName(req.params.repo)) { + reply.code(400).send({ error: "Bad request" }); + return; } const repository = await Repository.open(settings.base_dir, req.params.repo); @@ -151,11 +150,22 @@ fastify.route<Route>({ method: "GET", url: "/:repo([a-zA-Z0-9\\.\\-_]+)/refs/tags/:tag", handler: async(req, reply) => { - const repository = await Repository.open(settings.base_dir, req.params.repo); - const tag = await Tag.lookup(repository, req.params.tag); + if(!verifyRepoName(req.params.repo)) { + reply.code(400).send({ error: "Bad request" }); + return; + } + + const repository: Repository | BaseError = await Repository.open(settings.base_dir, req.params.repo).catch(err => err); + + if(repository instanceof BaseError) { + reply.code(repository.code).send(repository.message); + return; + } + + const tag = await Tag.lookup(repository, req.params.tag).catch(err => err); - if(!tag) { - reply.code(404).send("Tag not found!"); + if(tag instanceof BaseError) { + reply.code(tag.code).send(tag.message); return; } diff --git a/packages/server/src/git/blob.ts b/packages/server/src/git/blob.ts index aeb1381..e44a979 100644 --- a/packages/server/src/git/blob.ts +++ b/packages/server/src/git/blob.ts @@ -1,4 +1,5 @@ import { TreeEntry as NodeGitTreeEntry } from "nodegit"; +import { BlobError, createError } from "./error"; export class Blob { private _ng_tree_entry: NodeGitTreeEntry; @@ -8,6 +9,9 @@ export class Blob { } public async content(): Promise<string> { + if(!this._ng_tree_entry.isBlob()) { + throw(createError(BlobError, 500, "Not a blob")); + } return this._ng_tree_entry.isBlob() ? (await this._ng_tree_entry.getBlob()).toString() : ""; } }
\ No newline at end of file diff --git a/packages/server/src/git/branch.ts b/packages/server/src/git/branch.ts index 90241a0..163eca7 100644 --- a/packages/server/src/git/branch.ts +++ b/packages/server/src/git/branch.ts @@ -1,10 +1,15 @@ import { CommitSummary } from "./commit"; import { Reference } from "./reference"; import { Repository } from "./repository"; +import { Repository as NodeGitRepository } from "nodegit"; +import { BranchError, createError } from "./error"; export class Branch extends Reference { public async latestCommit(): Promise<CommitSummary> { - const latest_commit = this._owner.nodegitRepository.getBranchCommit(this._ng_reference); + const latest_commit = this._owner.nodegitRepository.getBranchCommit(this._ng_reference).catch(() => { + throw(createError(BranchError, 500, "Failed to get the latest commit")); + }); + return { id: (await latest_commit).sha(), message: (await latest_commit).message(), @@ -12,13 +17,19 @@ export class Branch extends Reference { }; } - public static async lookup(owner: Repository, branch: string): Promise<Branch | null> { + public static async lookup(owner: Repository, branch: string): Promise<Branch> { const reference = await owner.nodegitRepository.getBranch(branch).catch(err => { if(err.errno === -3) { - return null; + throw(createError(BranchError, 404, "Branch not found!")); } - throw(err); + throw(createError(BranchError, 500, "Something went wrong.")); }); - return reference ? new Branch(owner, reference) : null; + return new Branch(owner, reference); + } + + public static async lookupExists(ng_repository: NodeGitRepository, branch: string): Promise<boolean> { + return ng_repository.getBranch(branch) + .then(() => true) + .catch(() => false); } }
\ No newline at end of file diff --git a/packages/server/src/git/commit.ts b/packages/server/src/git/commit.ts index 4b3e44b..94afda0 100644 --- a/packages/server/src/git/commit.ts +++ b/packages/server/src/git/commit.ts @@ -1,5 +1,5 @@ import { Commit as NodeGitCommit, Oid as NodeGitOid } from "nodegit"; -import { Author } from "./misc"; +import { Author } from "../../../shared_types/src"; import { Diff } from "./diff"; import { Repository } from "./repository"; import { Tree } from "./tree"; @@ -66,4 +66,8 @@ export class Commit { .then(() => true) .catch(() => false); } + + public static async masterCommit(owner: Repository): Promise<Commit> { + return new Commit(owner, await owner.nodegitRepository.getMasterCommit()); + } }
\ No newline at end of file diff --git a/packages/server/src/git/error.ts b/packages/server/src/git/error.ts new file mode 100644 index 0000000..0429a6c --- /dev/null +++ b/packages/server/src/git/error.ts @@ -0,0 +1,49 @@ +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); + } +} + +type ErrorConstructorType<T> = new (code: number, message: string) => T; + +export function createError<E extends BaseError>(ErrorConstructor: ErrorConstructorType<E>, code: number, message: string): E { + return new ErrorConstructor(code, message); +}
\ No newline at end of file diff --git a/packages/server/src/git/misc.ts b/packages/server/src/git/misc.ts index fcfaf29..637cb8c 100644 --- a/packages/server/src/git/misc.ts +++ b/packages/server/src/git/misc.ts @@ -6,11 +6,6 @@ export async function findAsync<T>(arr: T[], callback: (t: T) => Promise<boolean return arr[index]; } -export type Author = { - name: string, - email: string -} - export function getFile(base_dir: string, repository: string, file: string): Promise<string | null> { return new Promise(resolve => { readFile(`${base_dir}/${repository}/${file}`, (err, content) => { diff --git a/packages/server/src/git/reference.ts b/packages/server/src/git/reference.ts index 36f1312..b24f72d 100644 --- a/packages/server/src/git/reference.ts +++ b/packages/server/src/git/reference.ts @@ -1,6 +1,16 @@ import { Reference as NodeGitReference } from "nodegit"; import { Repository } from "./repository"; +type ReferenceClass<T> = new(owner: Repository, reference: NodeGitReference) => T; + +export function isNodeGitReferenceBranch(ref: NodeGitReference): boolean { + return Boolean(ref.isBranch()); +} + +export function isNodeGitReferenceTag(ref: NodeGitReference): boolean { + return Boolean(ref.isTag()); +} + export abstract class Reference { protected _ng_reference: NodeGitReference; protected _owner: Repository; @@ -15,4 +25,9 @@ export abstract class Reference { this.id = reference.target().tostrS(); this.name = reference.shorthand(); } + + public static async all<T>(owner: Repository, Target: ReferenceClass<T>, ref_fn: (ref: NodeGitReference) => boolean): Promise<T[]> { + const references = await owner.nodegitRepository.getReferences(); + return references.filter(ref_fn).map(ref => new Target(owner, ref)); + } }
\ No newline at end of file diff --git a/packages/server/src/git/repository.ts b/packages/server/src/git/repository.ts index ff23761..c95edaa 100644 --- a/packages/server/src/git/repository.ts +++ b/packages/server/src/git/repository.ts @@ -7,6 +7,8 @@ import { Commit } from "./commit"; import { FastifyReply } from "fastify"; import { Tag } from "./tag"; import { Tree } from "./tree"; +import { BranchError, createError, RepositoryError } from "./error"; +import { isNodeGitReferenceBranch, isNodeGitReferenceTag, Reference } from "./reference"; function getFullRepositoryName(repo_name: string) { return repo_name.endsWith(".git") ? repo_name : `${repo_name}.git`; @@ -19,12 +21,21 @@ type RepositoryName = { type RepositoryConstructorData = { description: string | null, - owner: string | null + owner: string | null, + branch: string +} + +// This fucking shit isn't in the Nodegit documentation. +interface WeirdNodeGitError extends Error { + errno: number; + errorFunction: string; } export class Repository { private _ng_repository: NodeGitRepository; + private _branch: string; + public name: RepositoryName; public base_dir: string; public description: string | null; @@ -39,6 +50,12 @@ export class Repository { this.base_dir = dirname(repository.path()); this.description = data.description; this.owner = data.owner; + + this._branch = data.branch; + } + + public branch(): Promise<Branch> { + return Branch.lookup(this, this._branch); } public async commits(): Promise<Commit[]> { @@ -49,9 +66,7 @@ export class Repository { } public async tree(): Promise<Tree> { - const master_commit = await this._ng_repository.getMasterCommit(); - const tree = await master_commit.getTree(); - return new Tree(this, tree); + return Tree.ofRepository(this); } public lookupExists(id: string): Promise<boolean> { @@ -60,18 +75,16 @@ export class Repository { .catch(() => false); } - public async branches(): Promise<Branch[]> { - const references = await this._ng_repository.getReferences(); - return references.filter(ref => ref.isBranch()).map(branch => new Branch(this, branch)); + public branches(): Promise<Branch[]> { + return Reference.all(this, Branch, isNodeGitReferenceBranch); } public async tags(): Promise<Tag[]> { - const references = await this._ng_repository.getReferences(); - return references.filter(ref => ref.isTag()).map(tag => new Tag(this, tag)); + return Reference.all(this, Tag, isNodeGitReferenceTag); } - public async latestCommit(): Promise<Commit> { - return new Commit(this, await this._ng_repository.getMasterCommit()); + public async masterCommit(): Promise<Commit> { + return Commit.masterCommit(this); } public HTTPconnect(req: Request, reply: FastifyReply): void { @@ -82,12 +95,25 @@ export class Repository { return this._ng_repository; } - public static async open(base_dir: string, repository: string): Promise<Repository> { - const ng_repository = await NodeGitRepository.openBare(`${base_dir}/${getFullRepositoryName(repository)}`); + public static async open(base_dir: string, repository: string, branch?: string): Promise<Repository> { + let ng_repository = await NodeGitRepository.openBare(`${base_dir}/${getFullRepositoryName(repository)}`).catch((err: WeirdNodeGitError) => { + if(err.errno === -3) { + throw(createError(RepositoryError, 404, "Repository not found")); + } + + throw(createError(RepositoryError, 500, "Unknown error")); + }); + + if(branch) { + if(!await Branch.lookupExists(ng_repository, branch)) { + throw(createError(BranchError, 404, "Branch not found!")); + } + } return new Repository(ng_repository, { description: await getFile(base_dir, getFullRepositoryName(repository), "description"), - owner: await getFile(base_dir, getFullRepositoryName(repository), "owner") + owner: await getFile(base_dir, getFullRepositoryName(repository), "owner"), + branch: branch || "master" }); } diff --git a/packages/server/src/git/tag.ts b/packages/server/src/git/tag.ts index 64828e7..3063a25 100644 --- a/packages/server/src/git/tag.ts +++ b/packages/server/src/git/tag.ts @@ -1,6 +1,5 @@ import { Object as NodeGitObject, Tag as NodeGitTag } from "nodegit"; import { Pack, pack } from "tar-stream"; -import { Author } from "./misc"; import { Blob } from "./blob"; import { Commit } from "./commit"; import { FastifyReply } from "fastify"; @@ -10,6 +9,8 @@ import { Tree } from "./tree"; import { TreeEntry } from "./tree_entry"; import { createGzip } from "zlib"; import { pipeline } from "stream"; +import { createError, TagError } from "./error"; +import { Author } from "../../../shared_types/src"; async function addArchiveEntries(entries: TreeEntry[], repository: string, archive: Pack) { for(const tree_entry of entries) { @@ -69,14 +70,15 @@ export class Tag extends Reference { }); } - public static async lookup(owner: Repository, tag: string): Promise<Tag | null> { + public static async lookup(owner: Repository, tag: string): Promise<Tag> { const reference = await owner.nodegitRepository.getReference(tag).catch(err => { if(err.errno === -3) { - return null; + throw(createError(TagError, 404, "Tag not found")); } - throw(err); + throw(createError(TagError, 404, "Failed to get tag")); }); - return reference ? new Tag(owner, reference) : null; + + return new Tag(owner, reference); } }
\ No newline at end of file diff --git a/packages/server/src/git/tree.ts b/packages/server/src/git/tree.ts index 8697010..2cec528 100644 --- a/packages/server/src/git/tree.ts +++ b/packages/server/src/git/tree.ts @@ -2,6 +2,7 @@ import { Blob } from "./blob"; import { Tree as NodeGitTree } from "nodegit"; import { Repository } from "./repository"; import { TreeEntry } from "./tree_entry"; +import { createError, TreeError } from "./error"; export class Tree { private _ng_tree: NodeGitTree; @@ -16,18 +17,14 @@ export class Tree { return this._ng_tree.entries().map(entry => new TreeEntry(this._owner, entry)); } - public async find(path: string): Promise<Blob | Tree | null> { + public async find(path: string): Promise<Blob | Tree> { const entry = await this._ng_tree.getEntry(path).catch(err => { if(err.errno === -3) { - return null; + throw(createError(TreeError, 404, "Path not found")); } - throw(err); + throw(createError(TreeError, 500, "Failed to get tree path")); }); - if(!entry) { - return null; - } - return entry.isBlob() ? new Blob(entry) : new Tree(this._owner, await entry.getTree()); } @@ -36,4 +33,9 @@ export class Tree { .then(() => true) .catch(() => false); } + + public static async ofRepository(owner: Repository): Promise<Tree> { + const master_commit = await owner.masterCommit(); + return master_commit.tree(); + } }
\ No newline at end of file |