New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

grunt-build-control

Package Overview
Dependencies
Maintainers
2
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-build-control - npm Package Compare versions

Comparing version 0.1.8 to 0.2.0

test/scenarios/basic deployment/repo/dist/empty_file

15

Gruntfile.js

@@ -30,6 +30,16 @@ /*

tests: [
'test/mock-repo'
'test/mock'
]
},
watch: {
tests: {
files: ['tasks/**/*', 'test/**/*', '!**/test/mock/**'],
tasks: 'test',
options: {
atBegin: true
}
}
},
// Configuration to be run (and then tested).

@@ -59,2 +69,4 @@ buildcontrol: {

// Actually load this plugin's task(s).

@@ -66,2 +78,3 @@ grunt.loadTasks('tasks');

grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-nodeunit');

@@ -68,0 +81,0 @@ grunt.loadNpmTasks('grunt-mocha-test');

6

package.json
{
"name": "grunt-build-control",
"description": "Automate version control tasks for your project's built code. Keep built code in sync with source code, maintain multiple branches of built code, commit with automatic messages, and push to remote repositories.",
"version": "0.1.8",
"version": "0.2.0",
"homepage": "https://github.com/robwierzbowski/grunt-build-control",

@@ -39,3 +39,5 @@ "author": "Rob Wierzbowski <hello@robwierzbowski.com> (http://robwierzbowski)",

"grunt-contrib-nodeunit": "~0.1.2",
"grunt-mocha-test": "^0.12.1"
"grunt-contrib-watch": "^0.6.1",
"grunt-mocha-test": "^0.12.1",
"lodash": "^2.4.1"
},

@@ -42,0 +44,0 @@ "peerDependencies": {

@@ -69,2 +69,10 @@ # grunt-build-control

#### remoteBranch
Type: `String`
Default: `''`
The remote branch to push to. Common usage would be for Heroku's `master` branch
requirement.
#### login

@@ -71,0 +79,0 @@ Type: `String`

@@ -28,2 +28,3 @@ /*

remote: '../',
remoteBranch: '',
login: '',

@@ -145,2 +146,11 @@ token: '',

function verifyRepoBranchIsTracked() {
// attempt to track a branch from origin
// it may fail on times that the branch is already tracking another
// remote. There is no problem when that happens, nor does it have any affect
shelljs.exec('git branch --track ' + options.branch + ' origin/' + options.branch, {silent: true});
}
// Initialize git repo if one doesn't exist

@@ -259,4 +269,7 @@ function initGit () {

function gitPush () {
var branch = options.branch;
if (options.remoteBranch) branch += ':' + options.remoteBranch;
log.subhead('Pushing ' + options.branch + ' to ' + options.remote);
execWrap('git push ' + remoteName + ' ' + options.branch, false, true);
execWrap('git push ' + remoteName + ' ' + branch, false, true);

@@ -274,2 +287,3 @@ if (options.tag) {

assignTokens();
if (options.remote === '../') verifyRepoBranchIsTracked();

@@ -285,3 +299,3 @@ // Change working directory

// Regex to test for remote url
var remoteUrlRegex = new RegExp('.+[\\/:].+');
var remoteUrlRegex = new RegExp('[\/\\:]');
if(remoteUrlRegex.test(remoteName)) {

@@ -293,3 +307,3 @@ initRemote();

localBranchExists = shelljs.exec('git show-ref --verify --quiet refs/heads/' + options.branch, {silent: true}).code === 0;
remoteBranchExists = shelljs.exec('git ls-remote --exit-code ' + remoteName + ' ' + options.branch, {silent: true}).code === 0;
remoteBranchExists = shelljs.exec('git ls-remote --exit-code ' + remoteName + ' ' + options.remoteBranch || options.branch, {silent: true}).code === 0;

@@ -311,3 +325,3 @@ if (remoteBranchExists) {

// Create local branch that tracks remote
execWrap('git branch --track ' + options.branch + ' ' + remoteName + '/' + options.branch);
execWrap('git branch --track ' + options.branch + ' ' + remoteName + '/' + (options.remoteBranch || options.branch));
}

@@ -314,0 +328,0 @@ else if (!remoteBranchExists && !localBranchExists) {

@@ -6,2 +6,6 @@ # Tests

```
or
```bash
grunt watch:tests
```

@@ -14,5 +18,6 @@

tests.js - contains tests to be executed
mock-repo/ - [auto gen] testing area for any given scenario
mock/ - [auto gen] testing area for any given scenario
repo/ - repository to do tests on
remote/ - [auto gen] "remote", imagine it as a github repo
verify/ - [auto gen] `git clone remote verify` produces this folder
validate/ - [auto gen] `git clone remote validate` produces this folder
scenarios/ - different scenarios to be executed

@@ -24,11 +29,6 @@ exampleA/

#### Notes
All tests are executed with the relative path being: `test/mock-repo/`
All tests are executed with the relative path being: `test/mock/`
A quick little helper to watch and rerun tests (requires `npm install nodemon -g`)
```bash
nodemon -w test -w tasks/ -i test/mock-repo --exec 'grunt test'
```
# Usage Example/Workflow

@@ -47,5 +47,5 @@ Still confused?

The test case can be found in "/test/tests.js", high level is:
- it purges `mock-repo/`
- it copies `scenarios/basic deployment/**` to `mock-repo/`
- it changes working directory to `mock-repo/`
- it purges `mock/`
- it copies `scenarios/basic deployment/**` to `mock/`
- it changes working directory to `mock/`
- it executes the test case named `basic deployment`

@@ -57,3 +57,3 @@

- which executes `grunt default`
- which executes `git clone remote verify`
- which executes `git clone remote validate`
- it does validations

@@ -60,0 +60,0 @@ ```

@@ -10,2 +10,3 @@ /*jshint -W030 */

var should = require('chai').should();
var _ = require('lodash');

@@ -20,6 +21,9 @@

*
* - A scenario has a `gruntfile.js` configuration.
* - Each build task will upload to a mock repo (folder name is `remote`)
* - It then clones the remote to `verify`. Validations can be done in the `verify` folder
* A Scenario can contain:
* repo - the folder to contain the repository
* repo/gruntfile.js - the gruntfile to be tested
* remote - (optional) can contain a setup cloud repository
* validate - (will be overwritten) it is cloned from remote (used to validate a push)
*
**
* NOTE: this function DOES change the process's working directory to the `scenario` so that

@@ -29,6 +33,7 @@ * validations are easier access.

var execScenario = function(cb) {
var mockRepoDir = path.normalize(__dirname + '/mock-repo');
var mockRepoDir = path.normalize(__dirname + '/mock');
var distDir = path.join(mockRepoDir, 'repo');
var remoteDir = path.join(mockRepoDir, 'remote');
var verifyDir = path.join(mockRepoDir, 'verify');
var verifyDir = path.join(mockRepoDir, 'validate');

@@ -52,3 +57,3 @@

childProcess.exec(GRUNT_EXEC, {cwd: mockRepoDir}, function(err, stdout, stderr) {
childProcess.exec(GRUNT_EXEC, {cwd: distDir}, function(err, stdout, stderr) {
next(err, {stdout: stdout, stderr: stderr});

@@ -61,3 +66,3 @@ });

fs.removeSync(verifyDir); // since we're cloning from `remote/` we'll just remove the folder if it exists
childProcess.exec('git clone remote verify', {cwd: mockRepoDir}, function(err) {
childProcess.exec('git clone remote validate', {cwd: mockRepoDir}, function(err) {
if (err) throw new Error(err);

@@ -71,3 +76,3 @@ next(err);

// return results from executeGruntCommand
cb(err, results[1]);
cb(err, results[1].stdout, results[1].stderr);
});

@@ -86,22 +91,33 @@ };

* Assumptions:
* - each tests' current working directory has been set to `test/mock-repo`
* - each tests' current working directory has been set to `test/mock`
*/
describe('buildcontrol', function() {
this.timeout(10000);
this.timeout(6000);
beforeEach(function(done) {
var scenarioPath = this.currentTest.parent.title;
// ensure that we reset to `test/` dir
process.chdir(__dirname);
// clean testing folder `test/mock-repo`
fs.removeSync('mock-repo');
fs.ensureDirSync('mock-repo');
// clean testing folder `test/mock`
fs.removeSync('mock');
fs.ensureDirSync('mock');
// copy scenario to `test/mock-repo`
fs.copySync('scenarios/' + this.currentTest.parent.title, 'mock-repo');
try {
// copy scenario to `test/mock`
fs.copySync('scenarios/' + scenarioPath, 'mock');
// ensure all tests are are using the working directory: `test/mock-repo`
process.chdir('mock-repo');
done();
// ensure all tests are are using the working directory: `test/mock`
process.chdir('mock');
done();
}
catch (err) {
if (err && err.code === 'ENOENT')
throw new Error('could not find scenario "' + scenarioPath + '" in test/scenarios/');
throw new Error(err);
}
});

@@ -113,3 +129,3 @@

it('should have pushed a file and had the correct commit in "verify" repo', function(done) {
// the working directory is `test/mock-repo`.
// the working directory is `test/mock`.
var tasks = [];

@@ -120,3 +136,3 @@

*/
// make `mock-repo` a actual repository
// make `mock` a actual repository
tasks.push(function git_init(next) {

@@ -148,3 +164,3 @@ childProcess.exec('git init', next);

tasks.push(function verify_file_exists(next) {
fs.existsSync('verify/empty_file').should.be.true;
fs.existsSync('validate/empty_file').should.be.true;
next();

@@ -157,3 +173,3 @@ });

childProcess.exec('git log --pretty=oneline --no-color', {cwd: 'verify'}, function(err, stdout) {
childProcess.exec('git log --pretty=oneline --no-color', {cwd: 'validate'}, function(err, stdout) {
stdout.should.have.string('from commit ' + sha);

@@ -168,5 +184,2 @@ next();

});

@@ -177,5 +190,5 @@

it('merge multiple repos', function(done) {
execScenario(function(err, results) {
execScenario(function(err, stdout, stderr) {
should.not.exist(err);
var numberFile = fs.readFileSync('verify/numbers.txt', {encoding: 'utf8'});
var numberFile = fs.readFileSync('validate/numbers.txt', {encoding: 'utf8'});
numberFile.should.be.eql('0 1 2\n');

@@ -195,3 +208,3 @@ done();

execScenario(function() {
var numberFile = fs.readFileSync('verify/numbers.txt', {encoding: 'utf8'});
var numberFile = fs.readFileSync('validate/numbers.txt', {encoding: 'utf8'});
numberFile.should.be.eql('1 2 3 4\n');

@@ -203,6 +216,6 @@ next();

tasks.push(function(next) {
fs.writeFileSync('dist/numbers.txt', '100 200');
fs.writeFileSync('repo/dist/numbers.txt', '100 200');
execScenario(function(err, results) {
var numberFile = fs.readFileSync('verify/numbers.txt', {encoding: 'utf8'});
var numberFile = fs.readFileSync('validate/numbers.txt', {encoding: 'utf8'});
numberFile.should.be.eql('100 200');

@@ -214,3 +227,3 @@ next();

tasks.push(function(next) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'verify'}, function(err, stdout) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'validate'}, function(err, stdout) {
stdout.should.have.string('simple deploy commit message');

@@ -226,5 +239,5 @@ next();

it('should not have <TOKEN> in the message', function(done) {
execScenario(function(err, result) {
execScenario(function(err, stdout) {
should.not.exist(err);
result.stdout.should.not.have.string('<TOKEN>');
stdout.should.not.have.string('<TOKEN>');
done();

@@ -242,7 +255,7 @@ });

tasks.push(function(next) {
execScenario(function(err, results) {
results.stdout.should.not.have.string('privateUsername');
results.stdout.should.not.have.string('1234567890abcdef');
results.stdout.should.have.string('github.com/pubUsername/temp.git');
results.stdout.should.have.string('<CREDENTIALS>');
execScenario(function(err, stdout) {
stdout.should.not.have.string('privateUsername');
stdout.should.not.have.string('1234567890abcdef');
stdout.should.have.string('github.com/pubUsername/temp.git');
stdout.should.have.string('<CREDENTIALS>');
next();

@@ -266,3 +279,3 @@ });

tasks.push(function(next) {
childProcess.exec('git remote -v', {cwd: 'dist'}, function(err, stdout) {
childProcess.exec('git remote -v', {cwd: 'repo/dist'}, function(err, stdout) {
stdout.should.have.string('https://privateUsername:1234567890abcdef@github.com/pubUsername/temp.git');

@@ -278,2 +291,251 @@ next();

describe('untracked branch in src repo', function() {
it('should track a branch in ../ if it was untracked', function(done) {
var tasks = [];
tasks.push(function(next) {
fs.removeSync('repo');
childProcess.exec('git clone remote repo', next);
});
tasks.push(function(next) {
fs.ensureDirSync('repo/build');
fs.writeFileSync('repo/build/hello.txt', 'hello world!');
next();
});
//tasks.push(function(next) { childProcess.exec('git branch --track build origin/build', {cwd: 'repo'}, next); });
tasks.push(function(next) {
execScenario(function(err, stdout) {
next(err);
});
});
tasks.push(function(next) {
childProcess.exec('git checkout build', {cwd: 'repo'}, function(err, stdout) {
next();
});
});
tasks.push(function(next) {
childProcess.exec('git log', {cwd: 'repo'}, function(err, stdout) {
stdout.should.have.string('a build commit');
next();
});
});
async.series(tasks, done);
});
it('should not set tracking info it branch already exists', function(done) {
var tasks = [];
tasks.push(function(next) {
fs.removeSync('repo');
childProcess.exec('git clone remote repo', next);
});
tasks.push(function(next) {
childProcess.exec('git branch build', {cwd: 'repo'}, next);
});
tasks.push(function(next) {
fs.ensureDirSync('repo/build');
fs.writeFileSync('repo/build/hello.txt', 'hello world!');
next();
});
tasks.push(function(next) {
execScenario(function(err, stdout) {
next(err);
});
});
tasks.push(function(next) {
childProcess.exec('git branch -lvv', {cwd: 'repo'}, function(err, stdout) {
stdout.should.not.have.string('origin/build');
next();
});
});
async.series(tasks, done);
});
});
describe('remote urls', function() {
function generateRemote(url, cb) {
var tasks = [];
// read template
var gruntfile = fs.readFileSync('repo/gruntfile.js', {encoding: 'UTF8'});
// generate template
gruntfile = _.template(gruntfile, {remoteURL: url});
// write generated gruntfile
fs.writeFileSync('repo/gruntfile.js', gruntfile);
// execute grunt command
tasks.push(function(next) {
//options
GRUNT_EXEC += ' --no-color';
childProcess.exec(GRUNT_EXEC, {cwd: 'repo'}, function(err, stdout, stderr) {
// mask error because remote paths may not exist
next(null, {stdout: stdout, stderr: stderr});
});
});
// get remote url
tasks.push(function(next) {
childProcess.exec('git remote -v', {cwd: 'repo/dist'}, function(err, stdout) {
next(err, stdout);
});
});
// callback
async.series(tasks, function(err, results) {
cb(err, results[1]);
});
}
var shouldMatch = [
'/path/to/repo.git/',
'path/to/repo.git/',
'/path/to/repo',
//'\\\\path\\\\to\\\\repo', // assuming works, there's a lot of escaping to be done
'path/to/repo',
'C:/user/repo',
'file:///path/to/repo.git/',
'git://git.com/~user/path/to/repo.git/',
'http://git.com/path/to/repo.git/',
'https://github.com/user/repo',
'ssh://user@server/project.git',
'user@server:project.git',
'../'
];
async.each(shouldMatch, function(url) {
it('should have created remote for: ' + url, function(done) {
generateRemote(url, function(err, remoteURL) {
remoteURL.should.have.string(url);
done();
});
});
});
var shouldNotMatch = [
'origin',
'weird$1+name',
'remote_name',
'remote_name_extended',
'remote-name',
'remote.test'
];
async.each(shouldNotMatch, function(url) {
it('should not have created remote for: ' + url, function(done) {
generateRemote(url, function(err, remoteURL) {
remoteURL.should.not.have.string(url);
remoteURL.should.be.empty;
done();
});
});
});
});
describe('push diff branches', function() {
it('should push local:stage to stage:master and local:prod to prod:master', function(done) {
var tasks = [];
tasks.push(function(next) {
execScenario(function(err, stdout) {
fs.removeSync('validate'); // not needed because there's two diff remotes
next(err);
});
});
tasks.push(function(next) {
fs.removeSync('stage_validate');
childProcess.exec('git clone stage_remote stage_validate', next);
});
tasks.push(function(next) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'stage_validate'}, function(err, stdout) {
stdout.should.have.string('first stage commit');
stdout.should.have.string('new stage commit');
next();
});
});
tasks.push(function(next) {
fs.removeSync('prod_validate');
childProcess.exec('git clone prod_remote prod_validate', next);
});
tasks.push(function(next) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'prod_validate'}, function(err, stdout) {
stdout.should.have.string('first prod commit');
stdout.should.have.string('new prod commit');
next();
});
});
async.series(tasks, done);
});
it('should do it multiple times', function(done) {
var tasks = [];
tasks.push(function(next) {
execScenario(next);
});
tasks.push(function(next) {
fs.writeFileSync('repo/dist/empty_file', 'file not empty anymore');
next();
});
tasks.push(function(next) {
execScenario(next);
});
tasks.push(function(next) {
childProcess.exec('git clone stage_remote stage_validate', next);
});
tasks.push(function(next) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'stage_validate'}, function(err, stdout) {
stdout.match(/new stage commit/g).should.be.length(2);
next();
});
});
tasks.push(function(next) {
childProcess.exec('git clone prod_remote prod_validate', next);
});
tasks.push(function(next) {
childProcess.exec('git log --pretty=oneline --abbrev-commit --no-color', {cwd: 'prod_validate'}, function(err, stdout) {
stdout.match(/new prod commit/g).should.be.length(2);
next();
});
});
async.series(tasks, done);
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc