Skip to content

Commit

Permalink
feat(roadmap): Add Roadmap Interface
Browse files Browse the repository at this point in the history
  • Loading branch information
nprail committed Jun 16, 2018
0 parents commit 542fdd3
Show file tree
Hide file tree
Showing 21 changed files with 9,666 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "standard"
}
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

# package directories
node_modules
jspm_packages

# Serverless directories
.serverless
config.yml
.env
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Filiosoft, LLC

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<h1 align="center">GitLab Roadmap</h1>

<p align="center">
<a href="https://github.com/Filiosoft/gitlab-roadmap/blob/master/LICENSE"><img src="https://img.shields.io/github/license/Filiosoft/gitlab-roadmap.svg" alt="GitHub license"></a>
<a href="https://travis-ci.com/Filiosoft/gitlab-roadmap"><img src="https://travis-ci.com/Filiosoft/gitlab-roadmap.svg?branch=master" alt="Build Status"></a>
<a href="http://commitizen.github.io/cz-cli/"><img src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" alt="Commitizen friendly"></a>
<a href="https://standardjs.com"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="JavaScript Style Guide"></a>

</p>
<p align="center"><b>📢 Create a product roadmap website with GitLab Issue Boards as a backend!</b></p>

## Quick Start

Click the button below to deploy on Heroku!

[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)

## Install on AWS Lambda

Copy `config.example.yml` to `config.yml` and edit it to your liking

```
$ cp config.example.yml config.yml
```

Install the dependencies

```
$ npm install
```

And then run the following:

```
$ npx sls deploy
```

## License

[MIT](LICENSE)
52 changes: 52 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const express = require('express')

const { internalConfig, config } = require('./config/config')()
const axios = require('./config/axios')(internalConfig)

const app = express()

// setup express app
require('./config/express')(app)

app.get('/', async (req, res, next) => {
try {
const resp = await Promise.all([
axios.get(`/boards/${internalConfig.board_id}`),
axios.get('/?statistics=true')
])
const boardResp = resp[0]
const projectResp = resp[1]
const lists = boardResp.data.lists
const project = projectResp.data

if (boardResp.status !== 200) {
const err = new Error(
`Non-200 response code from GitLab: ${boardResp.status}`
)
err.status = boardResp.status
return next(err)
}

const maps = lists.map(async list => {
const resp = await axios.get(`/issues?labels=${list.label.name}`)
list.issues = resp.data
list.noIssues = list.issues.length < 1
})

await Promise.all(maps)

const sendData = {
lists,
project,
config
}
return res.render('home', sendData)
} catch (err) {
return next(err)
}
})

// setup error handlers
require('./lib/errorHandler')(app)

module.exports = app
44 changes: 44 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "GitLab Roadmap",
"description":
"📢 Create a product roadmap website with GitLab Issue Boards as a backend!",
"keywords": ["gitlab", "roadmap", "product"],
"website": "https://filiosoft.org/gitlab-roadmap",
"repository": "https://github.com/filiosoft/gitlab-roadmap",
"success_url": "/",
"env": {
"GL_RM_INT_CONFIG_TOKEN": {
"description": "GitLab personal access token",
"required": true
},
"GL_RM_INT_CONFIG_URL": {
"description": "GitLab instance address",
"value": "https://gitlab.com",
"required": true
},
"GL_RM_INT_CONFIG_PROJECT_ID": {
"description": "ID of GitLab project with roadmap issue board",
"value": "filiosoft/roadmap",
"required": true
},
"GL_RM_INT_CONFIG_BOARD_ID": {
"description": "ID of GitLab issue board",
"required": true
},
"GL_RM_CONFIG_THEME": {
"description": "Bootstrap CSS theme",
"value": "https://bootswatch.com/4/materia/bootstrap.min.css"
},
"GL_RM_CONFIG_LINK": {
"description": "Navbar brand link",
"value": "https://filiosoft.com"
},
"GL_RM_CONFIG_NAVBAR_CLASS": {
"description": "Navbar coloring classes (e.g. 'navbar-dark bg-dark')"
},
"GL_RM_CONFIG_COPYRIGHT": {
"description": "Copyright text",
"value": "Copyright &copy; 2018 Filiosoft, LLC"
}
}
}
83 changes: 83 additions & 0 deletions bin/www.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

const app = require('../app')
const http = require('http')

/**
* Get port from environment and store in Express.
*/

const port = normalizePort(process.env.PORT || '3000')
app.set('port', port)

/**
* Create HTTP server.
*/

const server = http.createServer(app)

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort (val) {
const port = parseInt(val, 10)

if (isNaN(port)) {
// named pipe
return val
}

if (port >= 0) {
// port number
return port
}

return false
}

/**
* Event listener for HTTP server "error" event.
*/

function onError (error) {
if (error.syscall !== 'listen') {
throw error
}

const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
default:
throw error
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening () {
const addr = server.address()
const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port
console.log('Listening on ' + bind)
}

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port)
server.on('error', onError)
server.on('listening', onListening)
11 changes: 11 additions & 0 deletions config.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
internal-config:
token: gitlab-personal-access-token # gitlab personal access token
url: https://gitlab.com # gitlab instance address
project-id: filiosoft/roadmap # can be ID or path
board-id: 49 # issue board ID
config:
theme: https://bootswatch.com/4/materia/bootstrap.min.css # boostrap theme
domain: roadmap.filiosoft.com # domain to deploy to
link: https://filiosoft.com # navbar brand link
# navbar-class: "navbar-dark bg-dark" # navbar coloring classes
copyright: "Copyright &copy; 2018 Filiosoft, LLC" # copyright text
16 changes: 16 additions & 0 deletions config/axios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const axios = require('axios')

const setupAxios = internalConfig => {
const axiosInstance = axios.create({
baseURL: `${internalConfig.url}/api/v4/projects/${encodeURIComponent(
internalConfig.project_id
)}`,
headers: {
'Private-Token': internalConfig.token
}
})

return axiosInstance
}

module.exports = setupAxios
31 changes: 31 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require('dotenv').config()

const getConfig = () => {
const internalConfig = {}
const config = {}

// convert undefined string to actual undefined
const convertUndefined = input => {
if (input === 'undefined') {
return undefined
}
return input
}

const loadConfig = (prefix, object) => {
for (const key in process.env) {
if (key.startsWith(prefix)) {
const newValue = convertUndefined(process.env[key])
const newKey = key.replace(prefix, '').toLowerCase()

object[newKey] = newValue
}
}
}
loadConfig('GL_RM_CONFIG_', config)
loadConfig('GL_RM_INT_CONFIG_', internalConfig)

return { config, internalConfig }
}

module.exports = getConfig
20 changes: 20 additions & 0 deletions config/express.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const cors = require('cors')
const exphbs = require('express-handlebars')
const moment = require('moment')

module.exports = app => {
app.use(cors())
app.engine(
'.hbs',
exphbs({
extname: '.hbs',
defaultLayout: 'main',
helpers: {
moment: input => {
return moment(input).format('MMMM Do YYYY, h:mm:ss a')
}
}
})
)
app.set('view engine', '.hbs')
}
10 changes: 10 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
GL_RM_INT_CONFIG_TOKEN=gitlab-personal-access-token
GL_RM_INT_CONFIG_URL=https://gitlab.com
GL_RM_INT_CONFIG_PROJECT_ID=filiosoft/roadmap
GL_RM_INT_CONFIG_BOARD_ID=49

GL_RM_CONFIG_THEME=https://bootswatch.com/4/materia/bootstrap.min.css
GL_RM_CONFIG_DOMAIN=roadmap.filiosoft.com
GL_RM_CONFIG_LINK=https://filiosoft.com
# GL_RM_CONFIG_NAVBAR_CLASS="navbar-dark bg-dark"
GL_RM_CONFIG_COPYRIGHT="Copyright &copy; 2018 Filiosoft, LLC"
30 changes: 30 additions & 0 deletions lib/errorHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module.exports = app => {
app.use((err, req, res, next) => {
console.log(err)
console.log('Setting up error handlers')
const errorName = err.name ? err.name : 'InternalError'
const errorMessage = err.message ? err.message : 'Internal Server Error'
const errorStatus = err.status ? err.status : 500
const errStack =
app.get('env') === 'development' && err.stack ? err.stack : undefined

return res.status(errorStatus).render('error', {
name: errorName,
message: errorMessage,
code: errorStatus,
stack: errStack
})
})

// catch not found
app.use((req, res, next) => {
res.status(404)

// respond with json
return res.send({
name: 'NotFound',
message: 'Not found',
code: 404
})
})
}
Loading

0 comments on commit 542fdd3

Please sign in to comment.