diff --git a/.gitignore b/.gitignore index c67aac4..22904b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ -node_modules/* -src/jspm_packages/* \ No newline at end of file +node_modules/ +src/jspm_packages/ +dist/ + +# TODO: Remove +build.min.js +build.min.js.map diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ec30e24 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +node_js: +- '0.12' +before_install: +- npm install -g jspm +- jspm config registries.github.auth $RADIFY_JSPM_GITHUB_AUTH_TOKEN +before_script: +- npm install +- jspm install +script: gulp +env: + global: + secure: lPYM9GGMD1qyd4/zhRTGpipOtxHwtQ0EFxgNg9KjRBEMkTLHjeZI0JQNskn0E8ZYXbjYghdUFvXkAAED5F9d0igPRcuLtAau1iGnW2PGyK2rzHE/fpplWFYIdm65CtQP4hv0bEGw3UBx9WkFDqs7NiRTE5YiDh75woP88weI7oxqlfpJdyvMJgoSda87dBYkYVOHCaMGrLkXK3GQhR6eJ20WZIp0TCbiMYLEzpo45BDMZSf9K0yRPiJ9vA3bgWUJGqfW4Dt6k10pKD1Q5SE/WeingOphiBK5Lrfp+Y7i1JkOpPzRC5rDMwJJUbJQpUeAvrmDQCf9VUmrib2iBA5dpRAe4xgOmdNEZaJEjS9lSU+dOtcBHo9mrlJ9pEHSzJO7Q3oLQC8nq7bf/SP1ZlQUnWqtxM3eIUnkIYJTBtzzQkHC3qpa5OZvWHrJIGqj8E1Mafp+1YHhelCHhg+ePiy1sXUvWF+1w3FC8M3O51Q/9YhjetpoqeshjmMdwJaV/8+WMZBieFHLzgLGIySTK6YQUMkUppqmVg524AwTDmMvgfZtr8xN/eBX3SnrUZjW9ILk00qCU/Q6qc/6IczCRyaByBajG2jqePn0wM78F6fGUMVO2Cdpp0P3+uSzKDb8XA8Vp7T1c4JthZ2ljRgP/Lgp4lUD/qEO1qio4a36sd6OVjc= diff --git a/README.md b/README.md index 53f9814..2fb3bb5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/radify/PR.js.svg)](https://travis-ci.org/radify/PR.js) + # PR.js _Programatically validate pull requests against the [contribution guidelines](https://help.github.com/articles/setting-guidelines-for-repository-contributors/)_ @@ -34,7 +36,7 @@ Most projects have rules of some kind about how to submit pull requests, which o **Test** - - [`http://localhost:3003/test.html`](http://localhost:3003/test.html) + - `gulp test` ### Roadmap diff --git a/dist/app.min.css b/dist/app.min.css deleted file mode 100644 index 953a0d0..0000000 --- a/dist/app.min.css +++ /dev/null @@ -1 +0,0 @@ -.row.bottom,.row.top,body,html{overflow:hidden}.col.pulls,.col.repos{border-right:2px solid #fff}.btn,.owner .title a,form.homeForm button.start,form.homeForm button.start span.glyphicon,form.homeForm input.search{-webkit-transition:all .3s linear;-moz-transition:all .3s linear;-ms-transition:all .3s linear;-o-transition:all .3s linear}.owner img,footer img{vertical-align:middle}.owner .title a,footer a{text-transform:uppercase}body,html{background:#e5eaed;color:#4a5154;font-family:'Open Sans',sans-serif;height:100%;margin:0;min-width:320px;padding:0;position:relative}.row.top{height:40%}.row.bottom{height:50%}.col{float:left;height:100%;overflow:auto;padding:0 10px;width:33%}.col.repos{width:20%}.col.pulls{width:35%}.col.pull{width:45%}.col-body{margin:5px;overflow:auto}.repo{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-align:left}div.homeHeader,footer,form.homeForm{text-align:center}.results{margin:15px;height:92%;overflow:auto}.owner .title a:after,.well.pull:after{height:16px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);content:""}.note{font-style:italic;color:#999}.owner{background:#fff}.owner .title{display:inline}.owner .title a{color:#787f82;display:block;font-size:16px;font-weight:600;padding:30px 15px;position:relative}.owner .title a:after{background:#fff;bottom:-6px;border-radius:4px;background-clip:padding-box;display:block;left:30px;position:absolute;width:16px}.avatar,.owner img{border-radius:4px;background-clip:padding-box}.owner .title a img{margin-right:10px;opacity:.8}.owner .title a:focus img,.owner .title a:hover img,footer:hover{opacity:1}.owner .title a:focus,.owner .title a:hover{color:#4a5154;text-decoration:none}.owner img{max-height:51px}.owner div.headerLogo{position:absolute;right:22px;top:36px;width:120px}.pull p{display:inline;padding:1px;margin:0}.pull .title{font-size:24px;font-weight:600;letter-spacing:-.05em;line-height:130%;padding-bottom:20px;min-height:40px}.avatar{float:left;margin-right:10px;max-width:40px;max-height:40px}.search{padding:4px;width:300px}h4{margin-top:0}.well{background:#fff;border:none;box-shadow:none;padding:30px 15px;position:relative}.well.pull:after{background:#fff;top:-6px;border-radius:4px;background-clip:padding-box;display:block;left:15px;position:absolute;width:16px}.well img{max-width:100%}.btn{background:#94cd7e;border:none;color:#fff}.btn:focus,.btn:hover{background:#76bf59;color:#fff}div.home{height:100%;overflow:auto;position:absolute;top:0;width:100%}div.bottom,div.top{overflow:hidden;width:100%}div.homeHeader{background:#fff}div.homeHeader h1{margin:42px auto 30px;max-width:230px}div.homeHeader p{color:#787f82;font-size:32px;font-weight:300;margin-bottom:30px}form.homeForm{margin:8.5% 0}form.homeForm input.search{background:rgba(255,255,255,.6);border-radius:6px;background-clip:padding-box;border:none;box-shadow:0 0 0 1px #c9ccce;font-size:18px;max-width:600px;padding:16px 24px;width:100%}form.homeForm input.search:hover{background:#fff}form.homeForm input.search:focus{background:#fff;box-shadow:0 0 0 4px #c9e6be;outline:0}form.homeForm input.search::-webkit-input-placeholder{color:#c9ccce;font-weight:300}form.homeForm input.search:-moz-placeholder{color:#c9ccce;font-weight:300}form.homeForm input.search::-moz-placeholder{color:#c9ccce;font-weight:300}form.homeForm input.search:-ms-input-placeholder{color:#c9ccce;font-weight:300}form.homeForm button.start{background:#94cd7e;border-radius:6px;background-clip:padding-box;border:0;clear:both;color:#fff;display:block;font-size:24px;font-weight:600;margin:40px auto;padding:12px 0;width:230px}form.homeForm button.start span.glyphicon{position:relative;top:2px}form.homeForm button.start:focus,form.homeForm button.start:hover{background:#76bf59;outline:0}form.homeForm button.start:focus span.glyphicon,form.homeForm button.start:hover span.glyphicon{margin-left:10px}ul.nav-pills li.active a,ul.nav-pills li.active a:focus,ul.nav-pills li.active a:hover{background:#4a5154;color:#fff}ul.nav-pills a{background:#d9e0e5;color:#787f82;font-weight:700;-webkit-transition:all .15s linear;-moz-transition:all .15s linear;-ms-transition:all .15s linear;-o-transition:all .15s linear}ul.nav-pills a:focus,ul.nav-pills a:hover{background:#c7d2d8;box-shadow:inset 0 2px 0 0 rgba(0,0,0,.05);color:#4a5154}ul.nav-pills a:active{background:#c1cdd4;box-shadow:inset 0 2px 0 0 rgba(0,0,0,.15)}div.top{bottom:310px;zoom:1;padding:0;position:absolute;top:130px}div.top:after,div.top:before{content:"";display:table}div.top:after{clear:both}div.topWrapper{height:75%}.result-title{margin:0 0 15px;padding:5px 10px;background:#96c396;color:#eee}.result-title.failed{background:#d76464;color:#fff}.test-results{list-style-type:none;padding-left:5px}.test-results li{padding-right:5px}.result-item{padding:0 0 10px 8px}.result-item span{position:relative}.result-item.result-passed{color:#94cd7e}.result-item.result-failed{color:#cd7e7e}.result-item .well{margin-top:4px}.result-item .well p{margin-bottom:1px}.result-item.result-failed .well{border-color:#e9c8c8;background:#f6f6f6}div.bottom{bottom:50px;height:250px;position:absolute}footer{background:#d5dadd;border-top:1px solid rgba(0,0,0,.1);position:fixed;bottom:0;right:0;opacity:.8;padding:10px 0 8px;-webkit-transition:all .3s linear;-moz-transition:all .3s linear;-ms-transition:all .3s linear;-o-transition:all .3s linear;width:100%}footer img{height:25px}footer a{color:#8b9194;font-size:14px;font-weight:400;display:block;opacity:.8;padding:0 8px;text-decoration:none}footer a:hover{color:#595e60;opacity:1;text-decoration:none}footer span{display:none}@media only screen and (min-width:530px){div.homeHeader h1{margin:8.5% auto 6%}div.homeHeader p{margin-bottom:6%}form.homeForm input.search{font-size:24px}footer{text-align:right}footer a,footer span{display:inline}}@media only screen and (min-width:1420px){div.homeHeader h1{margin:118px auto 84px}div.homeHeader p,form.homeForm{margin-bottom:84px}form.homeForm{margin-top:84px}form.homeForm input.search{font-size:24px}footer{text-align:right}footer a,footer span{display:inline}} \ No newline at end of file diff --git a/dist/img/PRjs.svg b/dist/img/PRjs.svg deleted file mode 100644 index e055f59..0000000 --- a/dist/img/PRjs.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/img/radify.svg b/dist/img/radify.svg deleted file mode 100644 index caf71d1..0000000 --- a/dist/img/radify.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/gulp/build.js b/gulp/build.js new file mode 100644 index 0000000..adc3650 --- /dev/null +++ b/gulp/build.js @@ -0,0 +1,10 @@ +'use strict'; + +var gulp = require('gulp'); +var runSeq = require('run-sequence'); + +gulp.task('build', function(done) { + runSeq('clean', ['buildjs', 'buildcss', 'buildimg'], done); +}); + + diff --git a/gulp/buildcss.js b/gulp/buildcss.js new file mode 100644 index 0000000..608ae80 --- /dev/null +++ b/gulp/buildcss.js @@ -0,0 +1,19 @@ +'use strict'; + +var gulp = require('gulp'); +var autoprefixer = require('gulp-autoprefixer'); +var concat = require('gulp-concat'); +var minifyCss = require('gulp-minify-css'); +var rename = require('gulp-rename'); + +// Build CSS for distribution. +gulp.task('buildcss', function () { + gulp.src(global.paths.css) + .pipe(concat('app.css')) + .pipe(autoprefixer()) + .pipe(minifyCss()) + .pipe(rename({ + suffix: '.min' + })) + .pipe(gulp.dest(global.paths.dist)); +}); diff --git a/gulp/buildimg.js b/gulp/buildimg.js new file mode 100644 index 0000000..bd09d7f --- /dev/null +++ b/gulp/buildimg.js @@ -0,0 +1,16 @@ +'use strict'; + +var gulp = require('gulp'); +var imagemin = require('gulp-imagemin'); +var pngquant = require('imagemin-pngquant'); + +// Build images for distribution. +gulp.task('buildimg', function () { + gulp.src(global.paths.img) + .pipe(imagemin({ + progressive: true, + svgoPlugins: [{removeViewBox: false}], + use: [pngquant()] + })) + .pipe(gulp.dest(global.paths.dist + '/img')); +}); diff --git a/gulp/buildjs.js b/gulp/buildjs.js new file mode 100644 index 0000000..e06fca6 --- /dev/null +++ b/gulp/buildjs.js @@ -0,0 +1,16 @@ +'use strict'; + +var gulp = require('gulp'); +var exec = require('child_process').execSync; + +// Build JS for distribution. +gulp.task('buildjs', function () { + exec('npm run buildjs', function (err, stdout, stderr) { + if (err) { + throw err; + } + else { + console.log('Build complete!'); + } + }); +}); diff --git a/gulp/clean.js b/gulp/clean.js new file mode 100644 index 0000000..bd0c2d9 --- /dev/null +++ b/gulp/clean.js @@ -0,0 +1,9 @@ +'use strict'; + +var gulp = require('gulp'); +var del = require('del'); + +// Empty the build dir. +gulp.task('clean', function (done) { + del([global.paths.dist + '/*'], done); +}); diff --git a/gulp/serve.js b/gulp/serve.js new file mode 100644 index 0000000..90868b4 --- /dev/null +++ b/gulp/serve.js @@ -0,0 +1,15 @@ +'use strict'; + +var gulp = require('gulp'); +var connect = require('gulp-connect'); + +// Start local dev server. +gulp.task('serve', function() { + connect.server({ + root: global.paths.index, + port: 3003, + livereload: true + }); + + console.log("Demo server started at localhost:3003"); +}); diff --git a/gulp/test.js b/gulp/test.js new file mode 100644 index 0000000..af24763 --- /dev/null +++ b/gulp/test.js @@ -0,0 +1,10 @@ +'use strict'; + +require('babel-core/register'); + +var gulp = require('gulp'); +var jasmine = require('gulp-jasmine'); + +gulp.task('test', function () { + return gulp.src(global.paths.specs).pipe(jasmine({ includeStackTrace: true })); +}); diff --git a/gulpfile.js b/gulpfile.js index 1e2cd22..71caf43 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,11 +1,38 @@ +'use strict'; + +/* + * gulpfile.js + * =========== + * Rather than manage one giant configuration file responsible + * for creating multiple tasks, each task has been broken out into + * its own file in the 'gulp' folder. Any files in that directory get + * automatically required below. + * + * To add a new task, simply add a new task file in that directory. + */ + var gulp = require('gulp'); -var conn = require('gulp-connect'); +var requireDir = require('require-dir'); + +global.paths = { + // CSS sources + 'css': './css/*', + // Distribution folder. + 'dist': './dist', + // Image sources. + 'img': './img/*', + // TODO: replace with ./src or ./build + 'index': './', + // Sources folder. + 'src': './src', + // Specs folder. + 'spec': './spec', + // Specs glob. + 'specs': './spec/**/*Spec.js' +}; -gulp.task('serve', function() { - conn.server({ - root: __dirname, - port: 3003 - }); +// Require all tasks in the 'gulp' folder. +requireDir('./gulp', { recurse: false }); - console.log("Demo server started at localhost:3003"); -}); \ No newline at end of file +// Default task; test & build +gulp.task('default', ['test', 'build']); diff --git a/package.json b/package.json index 29d1ce3..e476ebf 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,11 @@ "name": "pr.js", "version": "0.1.1", "description": "Simple validation for pull request workflows", - "main": "index.js", - "scripts": {}, + "main": "index.html", + "scripts": { + "buildjs": "jspm bundle-sfx pr.js build.min.js --minify", + "test": "gulp test" + }, "author": { "name": "Radify, Inc.", "email": "line@radify.io", @@ -34,11 +37,23 @@ ], "dependencies": {}, "devDependencies": { + "babel-core": "^5.8.22", + "del": "^1.2.1", "gulp": "^3.9.0", + "gulp-autoprefixer": "^2.3.1", "gulp-babel": "^5.2.1", "gulp-concat": "^2.6.0", "gulp-connect": "^2.2.0", - "gulp-uglify": "^1.2.0" + "gulp-imagemin": "^2.3.0", + "gulp-jasmine": "^2.0.1", + "gulp-minify-css": "^1.2.0", + "gulp-rename": "^1.2.2", + "gulp-uglify": "^1.2.0", + "imagemin-pngquant": "^4.1.2", + "jasmine": "^2.3.2", + "jspm": "^0.16.1", + "require-dir": "^0.3.0", + "run-sequence": "^1.1.2" }, "bugs": { "url": "https://github.com/radify/PR.js/issues" diff --git a/spec/index.js b/spec/index.js deleted file mode 100644 index ef926f0..0000000 --- a/spec/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import jasmine from "jasmine"; -import jasmineHtml from "jasmineHtml"; -import jasmineBoot from "jasmineBoot"; - -import MessageSpec from "parsers/MessageSpec"; -import SubjectSpec from "parsers/SubjectSpec"; -import HasSubjectSpec from "rules/HasSubjectSpec"; -import SquashedCommitsSpec from "rules/SquashedCommitsSpec"; -import SubjectFormatSpec from "rules/SubjectFormatSpec"; - -if (typeof window !== undefined) window.onload(); diff --git a/spec/parsers/Message.js b/spec/parsers/MessageSpec.js similarity index 84% rename from spec/parsers/Message.js rename to spec/parsers/MessageSpec.js index ce5a244..abbead9 100644 --- a/spec/parsers/Message.js +++ b/spec/parsers/MessageSpec.js @@ -1,4 +1,4 @@ -import Message from "parsers/Message"; +import Message from "../../src/parsers/Message"; describe("parsers/Message", () => { it("should pull the first commit message from a PR, split into lines", () => { diff --git a/spec/parsers/Subject.js b/spec/parsers/SubjectSpec.js similarity index 95% rename from spec/parsers/Subject.js rename to spec/parsers/SubjectSpec.js index 0a81e5c..2c8468d 100644 --- a/spec/parsers/Subject.js +++ b/spec/parsers/SubjectSpec.js @@ -1,4 +1,4 @@ -import Subject from "parsers/Subject"; +import Subject from "../../src/parsers/Subject"; describe("parsers/Subject", () => { it("should split valid subject lines into object hash", () => { diff --git a/spec/rules/HasSubject.js b/spec/rules/HasSubjectSpec.js similarity index 92% rename from spec/rules/HasSubject.js rename to spec/rules/HasSubjectSpec.js index 2b2e140..b70e6b8 100644 --- a/spec/rules/HasSubject.js +++ b/spec/rules/HasSubjectSpec.js @@ -1,4 +1,4 @@ -import HasSubject from "rules/HasSubject"; +import HasSubject from "../../src/rules/HasSubject"; describe("rules/HasSubject", () => { diff --git a/spec/rules/SquashedCommits.js b/spec/rules/SquashedCommitsSpec.js similarity index 85% rename from spec/rules/SquashedCommits.js rename to spec/rules/SquashedCommitsSpec.js index 3a8d85d..6fdc7a5 100644 --- a/spec/rules/SquashedCommits.js +++ b/spec/rules/SquashedCommitsSpec.js @@ -1,4 +1,4 @@ -import SquashedCommits from "rules/SquashedCommits"; +import SquashedCommits from "../../src/rules/SquashedCommits"; describe("rules/SquashedCommits", () => { diff --git a/spec/rules/SubjectFormat.js b/spec/rules/SubjectFormatSpec.js similarity index 92% rename from spec/rules/SubjectFormat.js rename to spec/rules/SubjectFormatSpec.js index bfeba8b..20239cd 100644 --- a/spec/rules/SubjectFormat.js +++ b/spec/rules/SubjectFormatSpec.js @@ -1,4 +1,4 @@ -import SubjectFormat from "rules/SubjectFormat"; +import SubjectFormat from "../../src/rules/SubjectFormat"; describe("rules/SubjectFormat", () => { diff --git a/src/config.js b/src/config.js index 6d9d561..8f31dca 100644 --- a/src/config.js +++ b/src/config.js @@ -10,18 +10,16 @@ System.config({ paths: { "github:*": "jspm_packages/github/*", "npm:*": "jspm_packages/npm/*", - "*Spec": "../spec/*.js", - "jasmineBoot": "https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.js", - "jasmineHtml": "https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.js", - "jasmine": "https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.js" + "*Spec": "../spec/*.js" }, map: { "angular": "npm:angular@1.4.0-rc.2", "angular-ui-router": "npm:angular-ui-router@0.2.15", "babel": "npm:babel-core@5.8.22", - "babel-runtime": "npm:babel-runtime@5.8.20", - "core-js": "npm:core-js@1.1.1", + "babel-core": "npm:babel-core@5.8.22", + "babel-runtime": "npm:babel-runtime@5.2.17", + "core-js": "npm:core-js@0.9.8", "marked": "npm:marked@0.3.3", "ramda": "npm:ramda@0.14.0", "github:jspm/nodelibs-process@0.1.1": { @@ -33,14 +31,9 @@ System.config({ "npm:angular@1.4.0-rc.2": { "process": "github:jspm/nodelibs-process@0.1.1" }, - "npm:babel-runtime@5.8.20": { + "npm:core-js@0.9.8": { "process": "github:jspm/nodelibs-process@0.1.1" }, - "npm:core-js@1.1.1": { - "fs": "github:jspm/nodelibs-fs@0.1.2", - "process": "github:jspm/nodelibs-process@0.1.1", - "systemjs-json": "github:systemjs/plugin-json@0.1.0" - }, "npm:ramda@0.14.0": { "process": "github:jspm/nodelibs-process@0.1.1" } diff --git a/test.html b/test.html deleted file mode 100644 index 2a8debc..0000000 --- a/test.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Jasmine Spec Runner: PR.js - - - - - - - - - - - - - - - - - - - - \ No newline at end of file