Skip to content

Commit

Permalink
feat: adds support for Data API in Github#getFileContents
Browse files Browse the repository at this point in the history
It brings a unified function for getting file contents with or without Data API.
fixed #546
  • Loading branch information
lancedikson committed Sep 11, 2020
1 parent ab092c8 commit 91ddc5b
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 13 deletions.
6 changes: 6 additions & 0 deletions __snapshots__/github.js

Large diffs are not rendered by default.

77 changes: 64 additions & 13 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,6 @@ export class GitHub {
updates: Update[],
defaultBranch: string
): Promise<Changes> {
const refName = `refs/heads/${defaultBranch}`;
const changes = new Map();
for (const update of updates) {
let content;
Expand All @@ -685,17 +684,11 @@ export class GitHub {
// hit GitHub again.
content = {data: update.contents};
} else {
content = await this.request(
`GET /repos/:owner/:repo/contents/:path${
this.proxyKey ? `?key=${this.proxyKey}` : ''
}`,
{
owner: this.owner,
repo: this.repo,
path: update.path,
ref: refName,
}
const fileContent = await this.getFileContents(
update.path,
defaultBranch
);
content = {data: fileContent};
}
} catch (err) {
if (err.status !== 404) throw err;
Expand Down Expand Up @@ -752,24 +745,82 @@ export class GitHub {
);
}

async getFileContents(path: string): Promise<GitHubFileContents> {
async getFileContentsWithSimpleAPI(
path: string,
defaultBranch: string | undefined
): Promise<GitHubFileContents> {
const options: any = {
owner: this.owner,
repo: this.repo,
path,
};
if (defaultBranch) {
options.ref = `refs/heads/${defaultBranch}`;
}
const resp = await this.request(
`GET /repos/:owner/:repo/contents/:path${
this.proxyKey ? `?key=${this.proxyKey}` : ''
}`,
options
);
return {
parsedContent: Buffer.from(resp.data.content, 'base64').toString('utf8'),
content: resp.data.content,
sha: resp.data.sha,
};
}

async getFileContentsWithDataAPI(
path: string,
defaultBranch: string | undefined
): Promise<GitHubFileContents> {
const repoTree = await this.request(
`GET /repos/:owner/:repo/git/trees/:branch${
this.proxyKey ? `?key=${this.proxyKey}` : ''
}`,
{
owner: this.owner,
repo: this.repo,
path,
branch: defaultBranch,
}
);

const blobDescriptor = repoTree.data.tree.find(
(tree: any) => tree.path === path
);

const resp = await this.request(
`GET /repos/:owner/:repo/git/blobs/:sha${
this.proxyKey ? `?key=${this.proxyKey}` : ''
}`,
{
owner: this.owner,
repo: this.repo,
sha: blobDescriptor.sha,
}
);

return {
parsedContent: Buffer.from(resp.data.content, 'base64').toString('utf8'),
content: resp.data.content,
sha: resp.data.sha,
};
}

async getFileContents(
path: string,
defaultBranch: string | undefined = undefined
): Promise<GitHubFileContents> {
try {
return await this.getFileContentsWithSimpleAPI(path, defaultBranch);
} catch (err) {
if (err.status === 403) {
return await this.getFileContentsWithDataAPI(path, defaultBranch);
}
throw err;
}
}

async createRelease(
packageName: string,
version: string,
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/github-data-api/403-too-large-file-response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"message": "This API returns blobs up to 1 MB in size. The requested blob is too large to fetch via the API, but you can use the Git Data API to request blobs up to 100 MB in size.",
"errors": [
{
"resource": "Blob",
"field": "data",
"code": "too_large"
}
],
"documentation_url": "https://docs.github.com/rest/reference/repos#get-repository-content"
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"sha": "1630d12c8e72e7f1441ae8afe2240d823c2d4804",
"url": "https://api.github.com/repos/lancedikson/release-please-403-example/git/trees/1630d12c8e72e7f1441ae8afe2240d823c2d4804",
"tree": [
{
"path": ".github",
"mode": "040000",
"type": "tree",
"sha": "cc64165cf5da91810ab7edc1143a47be42513c0a",
"url": "https://api.github.com/repos/lancedikson/release-please-403-example/git/trees/cc64165cf5da91810ab7edc1143a47be42513c0a"
},
{
"path": ".gitignore",
"mode": "100644",
"type": "blob",
"sha": "3c3629e647f5ddf82548912e337bea9826b434af",
"size": 13,
"url": "https://api.github.com/repos/lancedikson/release-please-403-example/git/blobs/3c3629e647f5ddf82548912e337bea9826b434af"
},
{
"path": "package-lock.json",
"mode": "100644",
"type": "blob",
"sha": "2f3d2c47bf49f81aca0df9ffc49524a213a2dc33",
"size": 1352120,
"url": "https://api.github.com/repos/lancedikson/release-please-403-example/git/blobs/2f3d2c47bf49f81aca0df9ffc49524a213a2dc33"
},
{
"path": "package.json",
"mode": "100644",
"type": "blob",
"sha": "33f90c139fca3d99a08a934fb87d30c13c68b885",
"size": 3995,
"url": "https://api.github.com/repos/lancedikson/release-please-403-example/git/blobs/33f90c139fca3d99a08a934fb87d30c13c68b885"
}
],
"truncated": false
}
62 changes: 62 additions & 0 deletions test/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,66 @@ describe('GitHub', () => {
req.done();
});
});

describe('getFileContents', () => {
it('should support Github Data API in case of a big file', async () => {
const simpleAPIResponse = JSON.parse(
readFileSync(
resolve(
fixturesPath,
'github-data-api',
'403-too-large-file-response.json'
),
'utf8'
)
);
const dataAPITreesResponse = JSON.parse(
readFileSync(
resolve(
fixturesPath,
'github-data-api',
'data-api-trees-successful-response.json'
),
'utf8'
)
);
const dataAPIBlobResponse = JSON.parse(
readFileSync(
resolve(
fixturesPath,
'github-data-api',
'data-api-blobs-successful-response.json'
),
'utf8'
)
);
const req1 = nock('https://api.github.com')
.get(
'/repos/fake/fake/contents/package-lock.json?ref=refs%2Fheads%2Fmaster'
)
.reply(403, simpleAPIResponse);
const req2 = nock('https://api.github.com')
.get('/repos/fake/fake/git/trees/master')
.reply(200, dataAPITreesResponse);
const req3 = nock('https://api.github.com')
.get(
'/repos/fake/fake/git/blobs/2f3d2c47bf49f81aca0df9ffc49524a213a2dc33'
)
.reply(200, dataAPIBlobResponse);

const fileContents = await github.getFileContents(
'package-lock.json',
'master'
);
expect(fileContents).to.have.property('content');
expect(fileContents).to.have.property('parsedContent');
expect(fileContents)
.to.have.property('sha')
.equal('2f3d2c47bf49f81aca0df9ffc49524a213a2dc33');
snapshot(fileContents);
req1.done();
req2.done();
req3.done();
});
});
});

0 comments on commit 91ddc5b

Please sign in to comment.