Fix: get files by path depth (#2993)
* fix: get files up to depth specified by colletion path * test(e2e): update mock data * chore: fix comment
This commit is contained in:
@ -11,6 +11,7 @@ import {
|
||||
onlySuccessfulPromises,
|
||||
resolvePromiseProperties,
|
||||
ResponseParser,
|
||||
basename,
|
||||
} from 'netlify-cms-lib-util';
|
||||
import {
|
||||
UsersGetAuthenticatedResponse as GitHubUser,
|
||||
@ -509,17 +510,20 @@ export default class API {
|
||||
});
|
||||
}
|
||||
|
||||
async listFiles(path: string, { repoURL = this.repoURL, branch = this.branch } = {}) {
|
||||
async listFiles(path: string, { repoURL = this.repoURL, branch = this.branch, depth = 1 } = {}) {
|
||||
const folder = trimStart(path, '/');
|
||||
return this.request(`${repoURL}/git/trees/${branch}:${folder}`, {
|
||||
params: { recursive: 10 },
|
||||
// GitHub API supports recursive=1 for getting the entire recursive tree
|
||||
// or omitting it to get the non-recursive tree
|
||||
params: depth > 1 ? { recursive: 1 } : {},
|
||||
})
|
||||
.then((res: GitHubTree) =>
|
||||
res.tree
|
||||
.filter(file => file.type === 'blob')
|
||||
// filter only files and up to the required depth
|
||||
.filter(file => file.type === 'blob' && file.path.split('/').length <= depth)
|
||||
.map(file => ({
|
||||
...file,
|
||||
name: file.path,
|
||||
name: basename(file.path),
|
||||
path: `${folder}/${file.path}`,
|
||||
})),
|
||||
)
|
||||
|
@ -187,7 +187,8 @@ export default class GraphQLAPI extends API {
|
||||
getAllFiles(entries, path) {
|
||||
const allFiles = entries.reduce((acc, item) => {
|
||||
if (item.type === 'tree') {
|
||||
return [...acc, ...this.getAllFiles(item.object.entries, `${path}/${item.name}`)];
|
||||
const entries = item.object?.entries || [];
|
||||
return [...acc, ...this.getAllFiles(entries, `${path}/${item.name}`)];
|
||||
} else if (item.type === 'blob') {
|
||||
return [
|
||||
...acc,
|
||||
@ -204,10 +205,10 @@ export default class GraphQLAPI extends API {
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
async listFiles(path, { repoURL = this.repoURL, branch = this.branch } = {}) {
|
||||
async listFiles(path, { repoURL = this.repoURL, branch = this.branch, depth = 1 } = {}) {
|
||||
const { owner, name } = this.getOwnerAndNameFromRepoUrl(repoURL);
|
||||
const { data } = await this.query({
|
||||
query: queries.files,
|
||||
query: queries.files(depth),
|
||||
variables: { owner, name, expression: `${branch}:${path}` },
|
||||
});
|
||||
|
||||
|
@ -489,4 +489,87 @@ describe('github API', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('listFiles', () => {
|
||||
it('should get files by depth', async () => {
|
||||
const api = new API({ branch: 'master', repo: 'owner/repo' });
|
||||
|
||||
const tree = [
|
||||
{
|
||||
path: 'post.md',
|
||||
type: 'blob',
|
||||
},
|
||||
{
|
||||
path: 'dir1',
|
||||
type: 'tree',
|
||||
},
|
||||
{
|
||||
path: 'dir1/nested-post.md',
|
||||
type: 'blob',
|
||||
},
|
||||
{
|
||||
path: 'dir1/dir2',
|
||||
type: 'tree',
|
||||
},
|
||||
{
|
||||
path: 'dir1/dir2/nested-post.md',
|
||||
type: 'blob',
|
||||
},
|
||||
];
|
||||
api.request = jest.fn().mockResolvedValue({ tree });
|
||||
|
||||
await expect(api.listFiles('posts', { depth: 1 })).resolves.toEqual([
|
||||
{
|
||||
path: 'posts/post.md',
|
||||
type: 'blob',
|
||||
name: 'post.md',
|
||||
},
|
||||
]);
|
||||
expect(api.request).toHaveBeenCalledTimes(1);
|
||||
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
|
||||
params: {},
|
||||
});
|
||||
|
||||
jest.clearAllMocks();
|
||||
await expect(api.listFiles('posts', { depth: 2 })).resolves.toEqual([
|
||||
{
|
||||
path: 'posts/post.md',
|
||||
type: 'blob',
|
||||
name: 'post.md',
|
||||
},
|
||||
{
|
||||
path: 'posts/dir1/nested-post.md',
|
||||
type: 'blob',
|
||||
name: 'nested-post.md',
|
||||
},
|
||||
]);
|
||||
expect(api.request).toHaveBeenCalledTimes(1);
|
||||
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
|
||||
params: { recursive: 1 },
|
||||
});
|
||||
|
||||
jest.clearAllMocks();
|
||||
await expect(api.listFiles('posts', { depth: 3 })).resolves.toEqual([
|
||||
{
|
||||
path: 'posts/post.md',
|
||||
type: 'blob',
|
||||
name: 'post.md',
|
||||
},
|
||||
{
|
||||
path: 'posts/dir1/nested-post.md',
|
||||
type: 'blob',
|
||||
name: 'nested-post.md',
|
||||
},
|
||||
{
|
||||
path: 'posts/dir1/dir2/nested-post.md',
|
||||
type: 'blob',
|
||||
name: 'nested-post.md',
|
||||
},
|
||||
]);
|
||||
expect(api.request).toHaveBeenCalledTimes(1);
|
||||
expect(api.request).toHaveBeenCalledWith('/repos/owner/repo/git/trees/master:posts', {
|
||||
params: { recursive: 1 },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import trimStart from 'lodash/trimStart';
|
||||
import semaphore from 'semaphore';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import { asyncLock, basename } from 'netlify-cms-lib-util';
|
||||
import { asyncLock, basename, getCollectionDepth } from 'netlify-cms-lib-util';
|
||||
import AuthenticationPage from './AuthenticationPage';
|
||||
import { get } from 'lodash';
|
||||
import API from './API';
|
||||
@ -256,7 +256,10 @@ export default class GitHub {
|
||||
|
||||
async entriesByFolder(collection, extension) {
|
||||
const repoURL = this.useOpenAuthoring ? this.api.originRepoURL : this.api.repoURL;
|
||||
const files = await this.api.listFiles(collection.get('folder'), { repoURL });
|
||||
const files = await this.api.listFiles(collection.get('folder'), {
|
||||
repoURL,
|
||||
depth: getCollectionDepth(collection),
|
||||
});
|
||||
const filteredFiles = files.filter(file => file.name.endsWith('.' + extension));
|
||||
return this.fetchFiles(filteredFiles, { repoURL });
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ export const statues = gql`
|
||||
${fragments.object}
|
||||
`;
|
||||
|
||||
const buildFilesQuery = (depth = 10) => {
|
||||
const buildFilesQuery = (depth = 1) => {
|
||||
const PLACE_HOLDER = 'PLACE_HOLDER';
|
||||
let query = oneLine`
|
||||
...ObjectParts
|
||||
@ -126,14 +126,12 @@ const buildFilesQuery = (depth = 10) => {
|
||||
return query;
|
||||
};
|
||||
|
||||
const filesQuery = buildFilesQuery();
|
||||
|
||||
export const files = gql`
|
||||
export const files = depth => gql`
|
||||
query files($owner: String!, $name: String!, $expression: String!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
...RepositoryParts
|
||||
object(expression: $expression) {
|
||||
${filesQuery}
|
||||
${buildFilesQuery(depth)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user