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:
Erez Rokah
2019-12-22 15:20:42 +02:00
committed by GitHub
parent 982fd7b0f8
commit b27748b54f
75 changed files with 4075 additions and 3714 deletions

View File

@ -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}`,
})),
)

View File

@ -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}` },
});

View File

@ -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 },
});
});
});
});

View File

@ -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 });
}

View File

@ -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)}
}
}
}