diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..19adfae Binary files /dev/null and b/.DS_Store differ diff --git a/.env b/.env new file mode 100644 index 0000000..17a07bd --- /dev/null +++ b/.env @@ -0,0 +1,12 @@ +PORT=3000 +DB_NAME=MaumasiFy +DB_USER=root +DB_PW= +DB_HOST=localhost +DB_SCHEMA=mysql +DB_PORT=3306 + +# Leave `DEBUG` as a blank value to be treated as false. +# In the terminal stop the server and type `DEBUG=true node server.js` to enable debugging +# logs show in the terminal. +DEBUG= diff --git a/.gitignore b/.gitignore index d118ef6..07dfa2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .DS_Store node_modules -test .env env.json *.log diff --git a/README.md b/README.md index 66f1f70..8f8e580 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Maumasi's Awesome URL Shortener! -`version: 1.5.0` +[ ![Codeship Status for Maumasi/URL_Shortener](https://app.codeship.com/projects/62acf700-7438-0134-4148-76a75a837005/status?branch=master)](https://app.codeship.com/projects/179118)
@@ -10,6 +10,9 @@ - [API Endpoints] (#user-content-api-endpoints) - [Usage] (#user-content-usage) - [Unit Testing] (#user-content-unit-testing) +- [Workflow] (#user-content-workflow) +- [Deployment] (#user-content-deployment) +- [Version Bumping] (#user-content-version-bumping)
___ @@ -314,4 +317,225 @@ Now you will get a robust output log of all major functions, models, and API rou At this time Unit Tests are run against all 6 API endpoints, all services under the serviceRepo directory, and all database CRUD models. - Feel free to add your own unit tests!! +Feel free to add your own unit tests!! + +___ +## Workflow +This section is meant for contributors.
+This project utilizes Git for version control. All instructions in this sections is in reference to ` git `. If you don't have *git* installed on your machine follow the instructions [here to get ` git ` up and running] (https://www.atlassian.com/git/tutorials/install-git) +
+ +The **master** branch is the main branch to contribute code but not the branch used for releasing production code. The production branch is called **release**. From the release branch we'll push out to a staging server as the last filter to catch any mistakes and then promote to a production server. +
+ +### Guidelines +- The **release branch** should not be edited directly +- New features should be built on a *feature branch* and tested before merged into the master branch +- Tag new releases using semantic versioning. Example: ` 1.1.2 ` correlates to **MAJOR.MINOR.PATCH** +
+ +### Git automation with **gulp** +The tool *gulp* is used to automate a few of the most common git tasks. Instead of changing the `version` of the API in the `URL_Shortener/package.json` gulp is programed to auto bump the specified version position. Additionally gulp will automatically stage all changes made, commit all changes and push everything up to the `origin` remote as long as that branch exists on the `origin`'s side of the remote. There are 3 gulp commands for making these version changes and git automation: +```bash + +# makes a 'patch' version bump and automates git commands to push to origin +# v1.0.0 becomes v1.0.1 +$ gulp patch + +# makes a 'minor' version bump and automates git commands to push to origin +# v1.0.0 becomes v1.1.0 +$ gulp minor + +# makes a 'major' version bump and automates git commands to push to origin +# v1.0.0 becomes v2.0.0 +$ gulp major + +``` + +### Patches +Patch concerns fixes only. Lower level patches such as mis-spelled words can be edited on the master branch. If many patch fixes are being made to the code functionality such as changing variable naming conventions then a feature brach should be created for that patch and that branch should be named after that patch such as *patch_1.1.2*. Follow the instructions below to create a feature branch for such a patch. +
+ +Create a new feature branch called patch_1.1.2: +```bash + +$ cd URL_Shortener/ +$ git checkout -b patch_1.1.2 +$ git add . +$ git commit -m "new feautre branch" +$ git push -u origin patch_1.1.2 + +``` +This will create the feature branch in the GitHub Repo as well as your local machine. +
+ +Inside this new branch you can make any changes you need to. Before trying to ` merge ` your patch to the **master** branch run the unit tests to make sure you're not committing broken code to the master branch. +```bash + +$ cd URL_Shortener/ +$ mocha + +``` +
+ +Only after all tests come back as 'passing' then you can merge the feature branch to the master branch. +```bash + +$ cd URL_Shortener/ +$ gulp push +$ git checkout master +$ git merge patch_1.1.2 +$ gulp --patch + +``` +
+ +Alternatively, if you to have a more verbose commit message you can follow these commands: +```bash + +$ cd URL_Shortener/ +$ git add . +$ git commit -m "version stable. A brief description of what this patch fixed." +$ git push +$ git checkout master +$ git merge patch_1.1.2 +$ git add . +$ git commit -m "merged the feature branch patch_1.1.2 to the master branch" +$ git push origin master + +``` +
+ +Now that the newly patched version of this project is on GitHub you should tag a new release named after the new version, **v1.1.2**. If you don't know how to create a new release [click here and follow GitHub's instructions] (https://help.github.com/articles/creating-releases/). +
+ +### Minor version updates +Adding a new feature to the API would be considered a minor version update. A new feature branch should be made for new features. To do this would be the same as the instructions as for making a patch feature branch except the name of the branch should be semantic to what the new feature is or does. +
+ +Create a new feature branch for the new feature: +```bash + +$ cd URL_Shortener/ +$ git checkout -b makeItRain + +``` + +You should see a returned log containing: +```bash + +Switched to a new branch 'makeItRain' + +``` +
+ +Inside this new branch you can start building the new makeItRain functionality, but first you should build a unit test(s) for makeItRain. Before trying to ` merge ` your patch to the **master** branch run the unit tests to make sure you're not committing broken code to the master branch. +```bash + +$ cd URL_Shortener/ +$ mocha + +``` +
+ +Only after all tests come back as 'passing' then you can merge the feature branch to the master branch. +```bash + +$ cd URL_Shortener/ +$ gulp push +$ git checkout master +$ git merge makeItRain +$ gulp --minor +``` +
+ +### Major version updates +A major version increase happens when the a change in the source code is not backwards compatible to previous versions. The instructions for this workflow is the same as for new feature minor version updates except to version bump up to a major version position the commands would look like this: +```bash + +$ cd URL_Shortener/ +$ gulp --major + +``` +
+ +___ +## Deployment + +### Setup +##### **Codeship** +- [Create a test for the master branch on Codeship] (https://codeship.com) +- [Set environment variables] (https://documentation.codeship.com/continuous-integration/set-environment-variables/) +- Setup test commands: + +
+*Setup Commands* +```bash + +nvm install 6.7.0 +nvm use 6.7.0 +npm install +npm install -g mocha + +``` +
+ +*Configur Test Pipelines* +```bash + +npm test + +``` + +##### **Heroku** +- [Create a pipeline] (https://devcenter.heroku.com/articles/pipelines) +- [Use clearDB as the API database by creating adding it as an add-on] (https://devcenter.heroku.com/articles/cleardb) +- [Set environment variables] (https://devcenter.heroku.com/articles/config-vars) +- [Connect GitHub to Heroku] (https://devcenter.heroku.com/articles/github-integration) + - Check the box labled 'Wait for CI to pass before deploy' +
+ +### Testing +After creating a test on Codeship for the master branch you can move on to run the test by making a push to the master branch. +```bash + +$ cd URL_Shortener/ +$ git checkout master +$ git add . +$ git commit -m "version stable. some changes that were made" +$ git push -u origin master + +``` +
+ +### Staging with Heroku +When adding clearDB as an add-on use the URI information as the environment variables. [Click here] (https://devcenter.heroku.com/articles/connecting-to-relational-databases-on-heroku-with-java) to see how to break apart a URI to find the database credentials. + +Anytime the release branch is pushed up to GitHub, the staging server on Heroku will rebuild as long as the master branch passed all the Codeship tests based on the latest master branch code. If all is well then the staging server can 'promote' the release branch code to the production server. To match the release branch to the master branch just merge master into release: +```bash + +$ cd URL_Shortener/ +$ git checkout release +$ git pull +$ git merge master +$ git push -u origin release + +``` +Note: +To avoid merge conflicts the release branch should never be edited directly as stated above under Guidelines in this section. + + +The staging server is used as the last filter before code is pushed over to the production server. Here we can see how the API runs on the planned server environment as well as testing functionality, looking for mis-spelled words, check that the API AJAX calls are working as expected. +
+ +### Production with Heroku +For the production server a different clearDB instance should be used as an add-on than the one used on the staging server. Make sure to use the production server's clearDB credentials in the environmental variables instead of the staging server's credentials. +
+ +**Important:** +An extra environment variable should be added to the list for the prodution server: +``` +NODE_ENV=production +``` + +After the staging server 'promotes' code over to the production server it should also be checked to make sure everything is working. Remember, this server is live and can be found by the public so it should be exactly the way you intended it to be. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..c23c2a7 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,76 @@ + +const gulp = require('gulp'); +const git = require('gulp-git'); +const replace = require('gulp-replace'); +const gitignore = require('gulp-gitignore'); +const argv = require('yargs').argv; + +const version = require('./package.json').version; + + +const versionBump = require('log-me').bump; + +const testit = versionBump(version, 'patch'); + +// The main gulp calls are at the very bottom of this file. Those main calls being: +// * gulp patch +// * gulp minor +// * gulp major + +// Run git add with options +gulp.task('add', () => { + return gulp.src('./*') + .pipe(gitignore()) + .pipe(git.add()); +}); + +// Run git commit +// src are the files to commit (or ./*) +gulp.task('commit', () => { + return gulp.src('./*') + .pipe(gitignore()) + .pipe(git.commit('auto commit')); +}); + +// Run git push +// remote is the remote repo +// branch is the remote branch to push to +gulp.task('push', () => { + git.push('origin', 'newLogger', (err) => { + if (err) throw err; + }); +}); + +// bump up the version according to 'patch', 'minor', 'major' +gulp.task('patchBump', () => { + console.log(testit); + gulp.src(['./package.json']) + .pipe(replace(`"version": "${version}"`, `"version": "${versionBump(version, 'patch')}"`)) + .pipe(gulp.dest('./')); +}); + +gulp.task('minorBump', () => { + gulp.src(['./package.json']) + .pipe(replace(`"version": "${version}"`, `"version": "${versionBump(version, 'minor')}"`)) + .pipe(gulp.dest('./')); +}); + +gulp.task('majorBump', () => { + gulp.src(['./package.json']) + .pipe(replace(`"version": "${version}"`, `"version": "${versionBump(version, 'major')}"`)) + .pipe(gulp.dest('./')); +}); + +// make version bumps by just calling the position bump as the flag +let bump = ''; +if (argv.patch) { + bump = 'patch'; +} else if (argv.minor) { + bump = 'minor'; +} else if (argv.major) { + bump = 'major'; +} + +gulp.task('default', [`${bump}Bump`, 'add', 'commit', 'push'], () => { +console.log(version); +}); diff --git a/logs/log.txt b/logs/log.txt deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index 1a43446..f1b8184 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "url-shortener", - "version": "1.5.0", + "version": "1.8.0", "description": "", "main": "index.js", "scripts": { @@ -30,7 +30,7 @@ "mysql": "^2.11.1", "request": "^2.75.0", "sequelize": "^3.24.3", - "log-me": "^1.0.4" + "log-me": "^1.0.14" }, "devDependencies": { "chai": "^3.5.0", @@ -39,8 +39,15 @@ "eslint-plugin-import": "^1.8.1", "eslint-plugin-jsx-a11y": "1.3.0", "eslint-plugin-react": "^5.1.1", + "gulp": "^3.9.1", + "gulp-git": "^1.11.3", + "gulp-git-streamed": "^1.8.0", + "gulp-gitignore": "^0.1.0", + "gulp-replace": "^0.5.4", + "log-me": "^1.0.12", "mocha": "^3.1.0", "nock": "^8.0.0", - "supertest": "^2.0.0" + "supertest": "^2.0.0", + "yargs": "^6.2.0" } } diff --git a/public/.DS_Store b/public/.DS_Store new file mode 100644 index 0000000..16a0e0a Binary files /dev/null and b/public/.DS_Store differ diff --git a/public/js/.DS_Store b/public/js/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/public/js/.DS_Store differ diff --git a/public/pages/.DS_Store b/public/pages/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/public/pages/.DS_Store differ diff --git a/server.js b/server.js index 10fd81f..26f3f90 100644 --- a/server.js +++ b/server.js @@ -3,10 +3,10 @@ const bodyParser = require('body-parser'); const express = require('express'); const sessions = require('express-session'); const routes = require('./src/routes/'); -const log = require('log-me'); +const log = require('log-me').print; + const app = express(); const PORT = process.env.PORT || 3000; -// require('dotenv').config(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); @@ -21,7 +21,6 @@ app.use('/', routes(express)); app.use(express.static('./public')); -// exports.server = const server = app.listen(PORT, () => { log(null, __filename, 'Server Active', diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/models/db.js b/src/models/db.js index 327781a..5a6bfd8 100644 --- a/src/models/db.js +++ b/src/models/db.js @@ -1,10 +1,6 @@ -// console.log('DB script reached'); const Sequelize = require('sequelize'); -// access environmental variables -// require('dotenv').config(); - // connect to the db const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PW, { host: process.env.DB_HOST, diff --git a/src/models/db_crud.js b/src/models/db_crud.js index 9b056a6..bc900cf 100644 --- a/src/models/db_crud.js +++ b/src/models/db_crud.js @@ -1,6 +1,6 @@ const db = require('./db'); -const log = require('log-me'); +const log = require('log-me').print; // obj of tables in the DB const tables = { diff --git a/src/routes/.DS_Store b/src/routes/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/routes/.DS_Store differ diff --git a/src/routes/apiEndPoints/deleteUrl.js b/src/routes/apiEndPoints/deleteUrl.js index 04ab390..f58c599 100644 --- a/src/routes/apiEndPoints/deleteUrl.js +++ b/src/routes/apiEndPoints/deleteUrl.js @@ -2,7 +2,7 @@ const maumasiFyURL = require('../../models/db_crud').table('maumasiFyURL'); const originalURL = require('../../models/db_crud').table('originalURL'); const shortKeyExtractor = require('../../services/services').services.shortKeyExtractor; -const log = require('log-me'); +const log = require('log-me').print; module.exports = (express) => { const router = express.Router(); diff --git a/src/routes/apiEndPoints/findAllUrls.js b/src/routes/apiEndPoints/findAllUrls.js index 2d32cfb..812922a 100644 --- a/src/routes/apiEndPoints/findAllUrls.js +++ b/src/routes/apiEndPoints/findAllUrls.js @@ -1,6 +1,6 @@ const maumasiFyURL = require('../../models/db_crud').table('maumasiFyURL'); -const log = require('log-me'); +const log = require('log-me').print; module.exports = (express) => { const router = express.Router(); diff --git a/src/routes/apiEndPoints/keyRedirect.js b/src/routes/apiEndPoints/keyRedirect.js index 7e92db1..774df59 100644 --- a/src/routes/apiEndPoints/keyRedirect.js +++ b/src/routes/apiEndPoints/keyRedirect.js @@ -1,6 +1,6 @@ const maumasiFyURL = require('../../models/db_crud').table('maumasiFyURL'); -const log = require('log-me'); +const log = require('log-me').print; module.exports = (express) => { const router = express.Router(); diff --git a/src/routes/apiEndPoints/shortenUrl.js b/src/routes/apiEndPoints/shortenUrl.js index 953d5d8..d76a903 100644 --- a/src/routes/apiEndPoints/shortenUrl.js +++ b/src/routes/apiEndPoints/shortenUrl.js @@ -1,7 +1,8 @@ const maumasiFyURL = require('../../models/db_crud').table('maumasiFyURL'); const originalURL = require('../../models/db_crud').table('originalURL'); -const log = require('log-me'); +const log = require('log-me').print; + // services const services = require('../../services/services').services; const rootUrlExists = services.rootUrlExists; diff --git a/src/routes/apiEndPoints/updateUrl.js b/src/routes/apiEndPoints/updateUrl.js index 6f0b6c6..6ba24c1 100644 --- a/src/routes/apiEndPoints/updateUrl.js +++ b/src/routes/apiEndPoints/updateUrl.js @@ -1,5 +1,6 @@ const maumasiFyURL = require('../../models/db_crud').table('maumasiFyURL'); -const log = require('log-me'); +const log = require('log-me').print; + // sevices const services = require('../../services/services').services; const shortKeyExtractor = services.shortKeyExtractor; diff --git a/src/services/serviceRepo/pingPreper.js b/src/services/serviceRepo/pingPreper.js index 0722547..575f05c 100644 --- a/src/services/serviceRepo/pingPreper.js +++ b/src/services/serviceRepo/pingPreper.js @@ -1,4 +1,4 @@ -const log = require('log-me'); +const log = require('log-me').print; module.exports = (url) => { // remove chars before host @@ -12,7 +12,6 @@ module.exports = (url) => { beforeHost = url.search('/') + 2; } - // console.log(beforeHost); const beginExtra = url.slice(0, beforeHost); const newUrl = url.replace(beginExtra, ''); diff --git a/src/services/serviceRepo/randomKeyMaker.js b/src/services/serviceRepo/randomKeyMaker.js index f87795e..1cadac2 100644 --- a/src/services/serviceRepo/randomKeyMaker.js +++ b/src/services/serviceRepo/randomKeyMaker.js @@ -1,5 +1,5 @@ -const log = require('log-me'); +const log = require('log-me').print; // private func that produces a random letter or number charactor function randomChar() { diff --git a/src/services/serviceRepo/rootUrlExists.js b/src/services/serviceRepo/rootUrlExists.js index 15c0081..a5551ec 100644 --- a/src/services/serviceRepo/rootUrlExists.js +++ b/src/services/serviceRepo/rootUrlExists.js @@ -1,4 +1,5 @@ -const log = require('log-me'); +const log = require('log-me').print; + const request = require('request'); module.exports = (url, callback) => { @@ -12,15 +13,7 @@ module.exports = (url, callback) => { request(options, () => { const isActive = true; - // const status = response.statusCode; - // if (!error && status <= 308) { - // isActive = true; - // } else { - // log(error, __filename, - // 'Service: rootUrlExists', - // `URL is unreachable with status code of: ${status}`); - // isActive = false; - // } + callback(isActive); }); }; diff --git a/src/services/serviceRepo/shortKeyExtractor.js b/src/services/serviceRepo/shortKeyExtractor.js index 59ada09..ee5f1bf 100644 --- a/src/services/serviceRepo/shortKeyExtractor.js +++ b/src/services/serviceRepo/shortKeyExtractor.js @@ -1,11 +1,9 @@ -const log = require('log-me'); +const log = require('log-me').print; module.exports = (shortLink) => { // remove chars before short link const beforeShortLink = shortLink.search('go/') + 3; - // console.log(beforeShortLink); - const beginExtra = shortLink.slice(0, beforeShortLink); const key = shortLink.replace(beginExtra, ''); diff --git a/test/_api_endpoints.js b/test/_api_endpoints.js index 84d1ae3..492a4e9 100644 --- a/test/_api_endpoints.js +++ b/test/_api_endpoints.js @@ -1,7 +1,8 @@ let server = require('../server.js'); const request = require('supertest'); -const log = require('log-me'); +const log = require('log-me').print; + const dummyRecord = require('./dummyData/dummyRecord'); const testKey = dummyRecord(); diff --git a/test/_api_models.js b/test/_api_models.js index aeeb5a9..a811e8f 100644 --- a/test/_api_models.js +++ b/test/_api_models.js @@ -1,6 +1,7 @@ const expect = require('chai').expect; -const log = require('log-me'); +const log = require('log-me').print; + const originalURL = require('../src/models/db_crud').table('originalURL'); const maumasiFyURL = require('../src/models/db_crud').table('maumasiFyURL'); diff --git a/test/_api_services.js b/test/_api_services.js index 21e386c..4c93945 100644 --- a/test/_api_services.js +++ b/test/_api_services.js @@ -1,6 +1,6 @@ const expect = require('chai').expect; -const log = require('log-me'); +const log = require('log-me').print; const services = require('../src/services/services').services; const pingPreper = services.pingPreper; diff --git a/test/dummyData/dummyRecord.js b/test/dummyData/dummyRecord.js index 49f06af..ee30302 100644 --- a/test/dummyData/dummyRecord.js +++ b/test/dummyData/dummyRecord.js @@ -1,6 +1,7 @@ const maumasiFyURL = require('../../src/models/db_crud').table('maumasiFyURL'); const originalURL = require('../../src/models/db_crud').table('originalURL'); -const log = require('log-me'); +const log = require('log-me').print; + // services const services = require('../../src/services/services').services; const randomKey = services.randomKey;