Skip to content

Commit

Permalink
Merge pull request #219 from ntsim/gitlab-support
Browse files Browse the repository at this point in the history
Add GitLab support
  • Loading branch information
eduardoboucas committed Aug 29, 2018
2 parents ea31c99 + d7e5e8f commit 55d1430
Show file tree
Hide file tree
Showing 40 changed files with 11,372 additions and 1,690 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -1,5 +1,9 @@
.idea/
*.iml

config.json
config.*.json
!config.test.json
!config.example.json
node_modules/
staticman_key
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -5,4 +5,4 @@ cache:
notifications:
email: false
node_js:
- '6'
- '8.11.3'
2 changes: 1 addition & 1 deletion Dockerfile
@@ -1,4 +1,4 @@
FROM node:6.7.0
FROM node:8.11.3

# Create app directory
RUN mkdir -p /app
Expand Down
5 changes: 3 additions & 2 deletions README.md
@@ -1,6 +1,6 @@
<img src="logo.png" width="300">

# Staticman [![coverage](https://img.shields.io/badge/coverage-53%25-red.svg?style=flat)](https://github.com/eduardoboucas/staticman) [![Build Status](https://travis-ci.org/eduardoboucas/staticman.svg?branch=master)](https://travis-ci.org/eduardoboucas/staticman) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
# Staticman [![coverage](https://img.shields.io/badge/coverage-82%25-yellow.svg?style=flat)](https://github.com/eduardoboucas/staticman) [![Build Status](https://travis-ci.org/eduardoboucas/staticman.svg?branch=master)](https://travis-ci.org/eduardoboucas/staticman) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

> Static sites with superpowers
Expand All @@ -14,7 +14,7 @@ You can download and run the Staticman API on your own infrastructure, or you ca

## Requirements

- Node.js 4.8.3+
- Node.js 8.11.3+
- npm
- A [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) for the GitHub account you want to run Staticman with
- An SSH key (click [here](https://help.github.com/articles/connecting-to-github-with-ssh/) to learn how to create one)
Expand Down Expand Up @@ -102,5 +102,6 @@ Would you like to contribute to Staticman? That's great! Here's how:
- [Tyne Time](https://www.tynetime.com) ([Source](https://github.com/Doocey/tyne-time-hugo))
- [BinaryMist](https://binarymist.io/blog) ([Source](https://github.com/binarymist/BinaryMistBlog))
- [La ruta de la cebada](https://larutadelacebada.com) ([Source](https://github.com/lasocial/larutadelacebada.github.io))
- [Gatsby Central](https://www.gatsbycentral.com) ([Source](https://github.com/GatsbyCentral/gatsbycentral.com))

Are you using Staticman? [Let us know!](https://github.com/eduardoboucas/staticman/edit/master/README.md)
30 changes: 30 additions & 0 deletions config.js
Expand Up @@ -54,12 +54,42 @@ const schema = {
default: 'development',
env: 'NODE_ENV'
},
githubAccessTokenUri: {
doc: 'URI for the GitHub authentication provider.',
format: String,
default: 'https://github.com/login/oauth/access_token',
env: 'GITHUB_ACCESS_TOKEN_URI'
},
githubBaseUrl: {
doc: 'Base URL for the GitHub API.',
format: String,
default: 'https://api.github.com',
env: 'GITHUB_BASE_URL'
},
githubToken: {
doc: 'Access token to the GitHub account being used to push files with.',
format: String,
default: null,
env: 'GITHUB_TOKEN'
},
gitlabAccessTokenUri: {
doc: 'URI for the GitLab authentication provider.',
format: String,
default: 'https://gitlab.com/oauth/token',
env: 'GITLAB_ACCESS_TOKEN_URI'
},
gitlabBaseUrl: {
doc: 'Base URL for the GitLab API.',
format: String,
default: 'https://gitlab.com',
env: 'GITLAB_BASE_URL'
},
gitlabToken: {
doc: 'Access token to the GitLab account being used to push files with.',
format: String,
default: null,
env: 'GITLAB_TOKEN'
},
port: {
doc: 'The port to bind the application to.',
format: 'port',
Expand Down
1 change: 1 addition & 0 deletions config.sample.json
@@ -1,4 +1,5 @@
{
"gitlabToken": "YOUR_GITLAB_TOKEN",
"githubToken": "YOUR_GITHUB_TOKEN",
"rsaPrivateKey": "-----BEGIN RSA PRIVATE KEY-----YOUR_KEY-----END RSA PRIVATE KEY-----",
"port": 80
Expand Down
1 change: 1 addition & 0 deletions config.test.json
@@ -1,4 +1,5 @@
{
"gitlabToken": "r4e3w2q1",
"githubToken": "1q2w3e4r",
"rsaPrivateKey": "-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEA2nX81/5w6nZLolEh0uKks3//FlqizKxFWi8GaEJYbud8FYwLH6l+LDfZkjQiDXvm6mxngDGCjlG9b7hgfa/sfWSuqtJUQ2D1Nenn11gwAUaI7OQNSassE+nVFL2BGedl6DOgpZFkKrDTQT7jyvvc3r/2IqWahAYyFWXImD50qwNWIGyZ2Sry2/WXeCydiUWV8ZG3GOlGZLgtlK8igdmLje/6Ja+1oRBFwdbWrf/nKsMB0fCL3R5MkWTnumR8sGx2Xud8Q3mF7cOYWQiy2AqrFQOzJ+QwH6hO6CGVk8eBh8xRkrjaZEsvolZ33N+0aS9NBxHuOyGq0Te9HMLFqwVGzwIDAQABAoIBAQDPD4gAnb0erdMQXT/m50TekdIQuQWXYy00xl+XUFMLg0L8FUmxz++0L5d72Qfxqd97kBYlzkeFZ3pbOvHSD33ieByJ8mNFnc+tMy+4z3BotRcxGRJzIdfcZAS/7MJB8C6KAO0iIQVE5WbGb7pu+XwmcOH1gutKeajc2SVhD8l7ECRARPuV3JxlhbVt+ylM05h7+5HwwnEmodNQHPeGvLEWp7eODNdcLLE5EFVjmN0dwGu9D+xCFna9bL7p921GOTGf349l3021ONaGvWd77Frhl9tHL1k40hqq4LiXDk3RkiP2oDb65+ohW128Q1QPgjMQuXbbFTCa3++pbz7OMbUhAoGBAPxt6A5B3s5GnnaCTE0YJ13aTeUyqrLimBxWEp7L/WXug8SDBW5tVAmBNHlZC4GuR089E7g26BVr0i3k/dOknKa0GLyGGJNphxrrcD05p+XB6Gd6/N1Yr6amM+8XqU1+UKLL2CBrLOSi6r4J4fPS8sb9362+FROwCJZfxd5Wznd/AoGBAN2NEz+anDBgulxLoguGuvc0FaqSsVIP/cdb5Ve5t29/uheVjLgDXSkV5P/RFfk1ygH1gNjmUrsoxfsGWQa3KMTk292maYRj7GPpOalSlp8BYyiQ9omPdOgusVzY4CEjMiDkKal0YrBswXKV8E2lTokEEkbdrQpToVdBmRCzT1ixAoGBAMNMBQ2CyO6ulEr75CyBU3O5QirhWE+uICFMNnvFNvd14VxYQgt9alcwL3jy+4QJYgJcLrWHRWfNU39Oe1MTOF+BVuIEnV7vdifNn7i+srd/nl7xOFHIG53DWMrSc5oQ8DIDo+LxCHqb0SHWY4pQ2qQ6JqQ1O/lPaFVvI5cxcevhAoGALyNtDQNgaAqsnCabe8hWz3INihVcFRHB9UDgMyIYnWiXt5ziK+TLVYqLBsL94eBH8tLBb2TSBXBPb3GST5N44SuwfCCEIt7/1OIymowv7/TjnCX7zpjvTtdgdVjPlz1d1RG2q49P0CnTnwW3801QwGZVXS6dOq1AjsguQRdlsoECgYBrFqKa3S48UbGOKkocgMb/1HzVs2sxNWMu+/jEiBvI4RrCiun9MALtrVtohgHRml4yZJaOojVk9F0z/MAak9eTgSmHpwxYZMqR1PvM4c/ekfun4hQoK04Thoexi/Z0RfsI6nBdBk8MAra03ldDvnYZY4Fat21YuNBspbrbTW8UoA==-----END RSA PRIVATE KEY-----",
"email": {
Expand Down
64 changes: 64 additions & 0 deletions controllers/auth.js
@@ -0,0 +1,64 @@
'use strict'

const gitFactory = require('../lib/GitServiceFactory')
const oauth = require('../lib/OAuth')
const RSA = require('../lib/RSA')
const Staticman = require('../lib/Staticman')

module.exports = (req, res) => {
const staticman = new Staticman(req.params)
staticman.setConfigPath()

let requestAccessToken

switch (req.params.service) {
case 'gitlab':
requestAccessToken = siteConfig =>
oauth.requestGitLabAccessToken(
req.query.code,
siteConfig.get('gitlabAuth.clientId'),
siteConfig.get('gitlabAuth.clientSecret'),
siteConfig.get('gitlabAuth.redirectUri')
)
break
default:
requestAccessToken = siteConfig =>
oauth.requestGitHubAccessToken(
req.query.code,
siteConfig.get('githubAuth.clientId'),
siteConfig.get('githubAuth.clientSecret'),
siteConfig.get('githubAuth.redirectUri')
)
}

return staticman.getSiteConfig()
.then(requestAccessToken)
.then((accessToken) => {
const git = gitFactory.create(req.params.service, {
oauthToken: accessToken
})

// TODO: Simplify this when v2 support is dropped.
const getUser = req.params.version === '2' && req.params.service === 'github'
? git.api.users.get({}).then(({data}) => data)
: git.getCurrentUser()

return getUser
.then((user) => {
res.send({
accessToken: RSA.encrypt(accessToken),
user
})
})
})
.catch((err) => {
console.log('ERR:', err)

const statusCode = err.statusCode || 401

res.status(statusCode).send({
statusCode,
message: err.message
})
})
}
13 changes: 6 additions & 7 deletions controllers/connect.js
Expand Up @@ -12,15 +12,14 @@ module.exports = (req, res) => {
const github = new GitHub({
username: req.params.username,
repository: req.params.repository,
branch: req.params.branch
branch: req.params.branch,
token: config.get('githubToken')
})

github.authenticateWithToken(config.get('githubToken'))
return github.api.users.getRepoInvites({}).then(({data}) => {
let invitationId = null

return github.api.users.getRepoInvites({}).then(response => {
let invitationId

const invitation = response.some(invitation => {
const invitation = data.some(invitation => {
if (invitation.repository.full_name === (req.params.username + '/' + req.params.repository)) {
invitationId = invitation.id

Expand All @@ -30,7 +29,7 @@ module.exports = (req, res) => {

if (invitation) {
return github.api.users.acceptRepoInvite({
id: invitationId
invitation_id: invitationId
})
} else {
res.status(404).send('Invitation not found')
Expand Down
32 changes: 0 additions & 32 deletions controllers/githubAuth.js

This file was deleted.

41 changes: 17 additions & 24 deletions controllers/handlePR.js
@@ -1,8 +1,7 @@
'use strict'

const path = require('path')
const config = require(path.join(__dirname, '/../config'))
const GitHub = require(path.join(__dirname, '/../lib/GitHub'))
const config = require('../config')
const GitHub = require('../lib/GitHub')
const Staticman = require('../lib/Staticman')

module.exports = (repo, data) => {
Expand All @@ -14,45 +13,39 @@ module.exports = (repo, data) => {
return
}

const github = new GitHub()
const github = new GitHub({
username: data.repository.owner.login,
repository: data.repository.name,
token: config.get('githubToken')
})

github.authenticateWithToken(config.get('githubToken'))
return github.getReview(data.number).then((review) => {
if (review.sourceBranch.indexOf('staticman_')) {
return null
}

return github.api.pullRequests.get({
user: data.repository.owner.login,
repo: data.repository.name,
number: data.number
}).then(response => {
if (response.head.ref.indexOf('staticman_')) {
if (review.state !== 'merged' && review.state !== 'closed') {
return null
}

if (response.merged) {
const bodyMatch = response.body.match(/(?:.*?)<!--staticman_notification:(.+?)-->(?:.*?)/i)
if (review.state === 'merged') {
const bodyMatch = review.body.match(/(?:.*?)<!--staticman_notification:(.+?)-->(?:.*?)/i)

if (bodyMatch && (bodyMatch.length === 2)) {
try {
const parsedBody = JSON.parse(bodyMatch[1])
const staticman = new Staticman(parsedBody.parameters)

staticman.authenticate()
staticman.setConfigPath(parsedBody.configPath)
staticman.processMerge(parsedBody.fields, parsedBody.options).catch(err => {
return Promise.reject(err)
})
staticman.processMerge(parsedBody.fields, parsedBody.options)
.catch(err => Promise.reject(err))
} catch (err) {
return Promise.reject(err)
}
}
}

if (response.state === 'closed') {
return github.api.gitdata.deleteReference({
user: data.repository.owner.login,
repo: data.repository.name,
ref: 'heads/' + response.head.ref
})
}
return github.deleteBranch(review.sourceBranch)
}).then(response => {
if (ua) {
ua.event('Hooks', 'Delete branch').send()
Expand Down
25 changes: 4 additions & 21 deletions controllers/process.js
Expand Up @@ -3,7 +3,6 @@
const path = require('path')
const config = require(path.join(__dirname, '/../config'))
const errorHandler = require('../lib/ErrorHandler')
const logger = require('../lib/Logger')
const reCaptcha = require('express-recaptcha')
const Staticman = require('../lib/Staticman')
const universalAnalytics = require('universal-analytics')
Expand Down Expand Up @@ -69,19 +68,6 @@ function process (staticman, req, res) {
const fields = req.query.fields || req.body.fields
const options = req.query.options || req.body.options || {}

logger.info(
JSON.stringify(
{
url: req.url,
fields,
options,
body: req.body
}
),
null,
2
)

return staticman.processEntry(fields, options).then(data => {
sendResponse(res, {
redirect: data.redirect,
Expand Down Expand Up @@ -137,20 +123,17 @@ function sendResponse (res, data) {
module.exports = (req, res, next) => {
const staticman = new Staticman(req.params)

staticman.authenticate()
staticman.setConfigPath()
staticman.setIp(req.headers['x-forwarded-for'] || req.connection.remoteAddress)
staticman.setUserAgent(req.headers['user-agent'])

return checkRecaptcha(staticman, req).then(usedRecaptcha => {
return process(staticman, req, res)
}).catch(err => {
return sendResponse(res, {
return checkRecaptcha(staticman, req)
.then(usedRecaptcha => process(staticman, req, res))
.catch(err => sendResponse(res, {
err,
redirect: req.body.options && req.body.options.redirect,
redirectError: req.body.options && req.body.options.redirectError
})
})
}))
}

module.exports.checkRecaptcha = checkRecaptcha
Expand Down

0 comments on commit 55d1430

Please sign in to comment.