Skip to content

Commit

Permalink
Add support for GitHub Apps
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Jan 12, 2019
1 parent 9ce2c48 commit d800786
Show file tree
Hide file tree
Showing 6 changed files with 5,734 additions and 4,053 deletions.
12 changes: 9 additions & 3 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,17 @@ const schema = {
default: 'https://api.github.com',
env: 'GITHUB_BASE_URL'
},
githubToken: {
doc: 'Access token to the GitHub account being used to push files with.',
githubAppID: {
doc: 'ID of the GitHub App.',
format: String,
default: null,
env: 'GITHUB_TOKEN'
env: 'GITHUB_INTEGRATION_ID'
},
githubPrivateKey: {
doc: 'Private key for the GitHub App.',
format: String,
default: null,
env: 'GITHUB_PRIVATE_KEY'
},
gitlabAccessTokenUri: {
doc: 'URI for the GitLab authentication provider.',
Expand Down
70 changes: 51 additions & 19 deletions lib/GitHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const config = require('../config')
const errorHandler = require('./ErrorHandler')
const githubApi = require('@octokit/rest')
const GitService = require('./GitService')
const jsonwebtoken = require('jsonwebtoken')
const Review = require('./models/Review')
const User = require('./models/User')

Expand All @@ -28,35 +29,66 @@ class GitHub extends GitService {
token: options.oauthToken
})
} else if (options.token) {
this.api.authenticate({
type: 'token',
token: options.token
})
this.authentication = this._authenticate(
options.username,
options.repository
)
} else {
throw new Error('Require an `oauthToken` or `token` option')
}
}

_authenticate (username, repository) {
const now = Math.floor(Date.now() / 1000)
const payload = {
iat: now,
exp: now + 60,
iss: config.get('githubAppID')
}
const bearer = jsonwebtoken.sign(payload, config.get('githubPrivateKey'), {
algorithm: 'RS256'
})

this.api.authenticate({
type: 'app',
token: bearer
})

return this.api.apps.findRepoInstallation({
owner: username,
repo: repository
}).then(({data}) => {
return this.api.apps.createInstallationToken({
installation_id: data.id
})
}).then(({data}) => {
this.api.authenticate({
type: 'token',
token: data.token
})
})
}

_pullFile (filePath, branch) {
return this.api.repos.getContents({
return this.authentication.then(() => this.api.repos.getContents({
owner: this.username,
repo: this.repository,
path: filePath,
ref: branch
})
}))
.then(normalizeResponse)
.catch(err => Promise.reject(errorHandler('GITHUB_READING_FILE', {err})))
}

_commitFile (filePath, content, commitMessage, branch) {
return this.api.repos.createFile({
return this.authentication.then(() => this.api.repos.createFile({
owner: this.username,
repo: this.repository,
path: filePath,
message: commitMessage,
content,
branch
})
}))
.then(normalizeResponse)
}

Expand Down Expand Up @@ -84,50 +116,50 @@ class GitHub extends GitService {
}

getBranchHeadCommit (branch) {
return this.api.repos.getBranch({
return this.authentication.then(() => this.api.repos.getBranch({
owner: this.username,
repo: this.repository,
branch
})
}))
.then(res => res.data.commit.sha)
}

createBranch (branch, sha) {
return this.api.gitdata.createReference({
return this.authentication.then(() => this.api.git.createRef({
owner: this.username,
repo: this.repository,
ref: `refs/heads/${branch}`,
sha
})
}))
.then(normalizeResponse)
}

deleteBranch (branch) {
return this.api.gitdata.deleteReference({
return this.authentication.then(() => this.api.git.deleteRef({
owner: this.username,
repo: this.repository,
ref: `heads/${branch}`
})
}))
}

createReview (reviewTitle, branch, reviewBody) {
return this.api.pullRequests.create({
return this.authentication.then(() => this.api.pullRequests.create({
owner: this.username,
repo: this.repository,
title: reviewTitle,
head: branch,
base: this.branch,
body: reviewBody
})
}))
.then(normalizeResponse)
}

getReview (reviewId) {
return this.api.pullRequests.get({
return this.authentication.then(() => this.api.pullRequests.get({
owner: this.username,
repo: this.repository,
number: reviewId
})
}))
.then(normalizeResponse)
.then(({base, body, head, merged, state, title}) =>
new Review(
Expand All @@ -151,7 +183,7 @@ class GitHub extends GitService {
}

getCurrentUser () {
return this.api.users.getAuthenticated({})
return this.authentication.then(() => this.api.users.getAuthenticated({}))
.then(normalizeResponse)
.then(({login, email, avatar_url, name, bio, company, blog}) =>
new User('github', login, email, name, avatar_url, bio, blog, company)
Expand Down
5 changes: 4 additions & 1 deletion lib/Staticman.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ const Staticman = function (parameters) {

const token = parameters.service === 'gitlab'
? config.get('gitlabToken')
: config.get('githubToken')
: {
integrationId: config.get('githubAppID'),
privateKey: config.get('githubPrivateKey')
}

// Initialise the Git service API
this.git = gitFactory.create(parameters.service, {
Expand Down
Loading

0 comments on commit d800786

Please sign in to comment.