diff --git a/packages/playground/storage/src/lib/git-sparse-checkout.spec.ts b/packages/playground/storage/src/lib/git-sparse-checkout.spec.ts index 6aa2ba10fc..68c10fe48c 100644 --- a/packages/playground/storage/src/lib/git-sparse-checkout.spec.ts +++ b/packages/playground/storage/src/lib/git-sparse-checkout.spec.ts @@ -1,8 +1,8 @@ -import { lsRefs, sparseCheckout } from './git-sparse-checkout'; +import { listRefs, sparseCheckout, listFiles } from './git-sparse-checkout'; -describe('lsRefs', () => { +describe('listRefs', () => { it('should return the latest commit hash for a given ref', async () => { - const refs = await lsRefs( + const refs = await listRefs( 'https://github.com/WordPress/wordpress-playground', 'refs/heads/trunk' ); @@ -25,3 +25,15 @@ describe('sparseCheckout', () => { expect(files['README.md'].length).toBeGreaterThan(0); }); }); + +describe.only('listFiles', () => { + it('should list the files in a git repo', async () => { + const files = await listFiles( + 'https://github.com/WordPress/wordpress-playground.git', + 'refs/heads/trunk' + ); + expect(files).toHaveProperty( + 'packages/playground/storage/package.json' + ); + }); +}); diff --git a/packages/playground/storage/src/lib/git-sparse-checkout.ts b/packages/playground/storage/src/lib/git-sparse-checkout.ts index 45675ccab8..3b7a786f3e 100644 --- a/packages/playground/storage/src/lib/git-sparse-checkout.ts +++ b/packages/playground/storage/src/lib/git-sparse-checkout.ts @@ -41,7 +41,7 @@ export async function sparseCheckout( fullyQualifiedBranchName: string, filesPaths: string[] ) { - const refs = await lsRefs(repoUrl, fullyQualifiedBranchName); + const refs = await listRefs(repoUrl, fullyQualifiedBranchName); const commitHash = refs[fullyQualifiedBranchName]; const treesIdx = await fetchWithoutBlobs(repoUrl, commitHash); const objects = await resolveObjects(treesIdx, commitHash, filesPaths); @@ -63,6 +63,34 @@ export async function sparseCheckout( return fetchedPaths; } +export async function listFiles( + repoUrl: string, + fullyQualifiedBranchName: string +) { + const refs = await listRefs(repoUrl, fullyQualifiedBranchName); + if (!(fullyQualifiedBranchName in refs)) { + throw new Error(`Branch ${fullyQualifiedBranchName} not found`); + } + const commitHash = refs[fullyQualifiedBranchName]; + const treesIdx = await fetchWithoutBlobs(repoUrl, commitHash); + const rootTree = await resolveAllObjects(treesIdx, commitHash); + const files: Record = {}; + function recurse(tree: GitTree, prefix = '') { + if (!tree?.object) { + return; + } + for (const branch of tree.object) { + if (branch.type === 'blob') { + files[prefix + branch.path] = branch.oid; + } else if (branch.type === 'tree' && branch.object) { + recurse(branch as any as GitTree, prefix + branch.path + '/'); + } + } + } + recurse(rootTree); + return files; +} + /** * Retrieves a list of files on matching git branches. * @@ -70,7 +98,7 @@ export async function sparseCheckout( * @param fullyQualifiedBranchPrefix The prefix of the branch names to fetch. For example: refs/heads/my-feature-branch * @returns A map of branch names to their corresponding commit hashes. */ -export async function lsRefs( +export async function listRefs( repoUrl: string, fullyQualifiedBranchPrefix: string ) { @@ -147,6 +175,30 @@ async function fetchWithoutBlobs(repoUrl: string, commitHash: string) { return idx; } +async function resolveAllObjects(idx: GitPackIndex, commitHash: string) { + const commit = await idx.read({ + oid: commitHash, + }); + readObject(commit); + + const rootItem = await idx.read({ oid: commit.object.tree }); + const items = [rootItem]; + while (items.length > 0) { + const tree = items.pop(); + const readItem = await idx.read({ oid: tree.oid }); + readObject(readItem); + tree.object = readItem.object; + if (readItem.type === 'tree') { + for (const subitem of readItem.object) { + if (subitem.type === 'tree') { + items.push(subitem); + } + } + } + } + return rootItem; +} + async function resolveObjects( idx: GitPackIndex, commitHash: string, diff --git a/types/isomorphic-git.d.ts b/types/isomorphic-git.d.ts index cb98db0f98..7b95b48ecf 100644 --- a/types/isomorphic-git.d.ts +++ b/types/isomorphic-git.d.ts @@ -10,11 +10,15 @@ declare module 'isomorphic-git/src/models/GitPktLine.js' { declare module 'isomorphic-git/src/models/GitTree.js' { export class GitTree { static from(buffer: Buffer): GitTree; - entries(): Array<{ + type: 'tree' | 'blob'; + oid: string; + format: 'content'; + object: Array<{ mode: string; path: string; oid: string; type?: 'blob' | 'tree'; + object?: GitTree; }>; } }