Skip to content

Instantly share code, notes, and snippets.

@j-fischer
Created December 22, 2017 05:29
Show Gist options
  • Save j-fischer/af781d18550c6b5b12730456cf4ddaab to your computer and use it in GitHub Desktop.
Save j-fischer/af781d18550c6b5b12730456cf4ddaab to your computer and use it in GitHub Desktop.
Sample Gruntfile and batch script to work with SFDX Projects
module.exports = function (grunt) {
// load all grunt tasks needed for this run
require('jit-grunt')(grunt);
// configurable paths
var config = {
module: 'force-app',
src: 'force-app/main/default',
test: 'force-app/test/default',
bundles: 'resource-bundles',
artifacts: {
build: '.tmp/build',
buildSrc: '.tmp/build/src',
jsdoc: '.tmp/docs',
root: '.tmp'
},
git: {
enabled: false,
commitMessage: "DEV - Changes detected by the automated Salesforce org export"
},
deployWaitTime: 10,
};
grunt.initConfig({
config: config,
env: process.env,
prompt: {
sfdcAlias: {
options: {
questions: [
{
config: 'env.SFALIAS',
type: 'input',
message: 'Salesforce DX Alias?',
when: function() {
if (grunt.config('env.SFALIAS')) {
grunt.log.ok('Using alias: ' + grunt.config('env.SFALIAS'));
return false;
}
return true;
}
},
]
}
},
sfdcPackage: {
options: {
questions: [
{
config: 'env.SFPACKAGE',
type: 'input',
message: 'Salesforce Package Name?',
when: function() {
return !grunt.config('env.SFPACKAGE');
}
},
]
}
},
},
clean: {
options: {
force: true
},
artifacts: '<%= config.artifacts.root %>',
profiles: '<%= config.artifacts.build %>/profiles'
},
mkdir: {
build: {
options: {
create: ['<%= config.artifacts.build %>']
}
}
},
todo: {
options: {
marks: [
{
name: "FIX",
pattern: /FIXME/,
color: "red"
},
{
name: "TODO",
pattern: /TODO/,
color: "yellow"
}
]
},
src: [
'*/<%= config.module %>/**/*.cls',
'*/<%= config.module %>/**/*.page',
'*/<%= config.bundles %>/**/*.js',
'*/<%= config.bundles %>/**/*.css',
'!*/<%= config.bundles %>/**/lib/*.js'
],
},
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
src: [
'Gruntfile.js',
'<%= config.bundles %>/{,*/}*.js'
]
},
package_folders: {
staticResources: {
options: {
extension: '',
deleteFolder: false
},
files: [{
filter: 'isDirectory',
cwd: '<%= config.bundles %>',
src: ['*'],
dest: '<%= config.src %>/staticresources'
}]
}
},
shell: {
'lightning-lint': {
command: 'sfdx force:lightning:lint <%= config.src %>/aura',
options: {
callback: function (err, stdout, stderr, cb) {
if (err) {
cb(err);
return;
}
var re = /\d+ problems? \([1-9] errors?, \d+ warnings\)/ig;
var result = re.exec(stdout);
if (result) {
cb(new Error("Found linting errors in lightning components"));
return;
}
cb();
}
}
},
'force-push': {
command: 'sfdx force:source:push -u <%= env.SFALIAS %>'
},
'force-pull': {
command: 'sfdx force:source:pull -u <%= env.SFALIAS %>'
},
'force-test': {
command: 'sfdx force:apex:test:run --resultformat human -u <%= env.SFALIAS %>'
},
'force-deploy': {
command: 'sfdx force:mdapi:deploy -u <%= env.SFALIAS %> -l RunLocalTests -w <%= config.deployWaitTime %> -d <%= config.artifacts.build %>',
},
'force-deploy-ignore-tests': {
command: 'sfdx force:mdapi:deploy -u <%= env.SFALIAS %> -l NoTestRun -w <%= config.deployWaitTime %> -d <%= config.artifacts.build %>',
},
'force-retrieve': {
command: 'sfdx force:mdapi:retrieve -u <%= env.SFALIAS %> -r <%= config.artifacts.build %> -p <%= env.SFPACKAGE %>',
},
'force-check-deploy': {
command: 'sfdx force:mdapi:deploy -u <%= env.SFALIAS %> -c -l RunLocalTests -w <%= config.deployWaitTime %> -d <%= config.artifacts.build %>',
},
'force-check-deploy-ignore-tests': {
command: 'sfdx force:mdapi:deploy -u <%= env.SFALIAS %> -c -w <%= config.deployWaitTime %> -l NoTestRun -d <%= config.artifacts.build %>',
},
'force-convert-source': {
command: 'sfdx force:source:convert -r <%= config.module %> -d <%= config.artifacts.build %>'
},
'force-convert-md': {
command: 'sfdx force:mdapi:convert -r <%= config.artifacts.buildSrc %>/'
},
'git-commit-changes': {
command: [
'git add -A',
'git commit -a -m "Changes detected by the automated Salesforce org export"',
'git push origin master'
].join('&&'),
options: {
execOptions: {
cwd: '<%= config.module %>'
}
}
}
}
});
grunt.registerMultiTask('package_folders', "Zips up static resources to the proper binary needed for deployments", function () {
/* NOTE: This is a bit of a hackish solution specifically for the configuration provided in package_folders.staticResource.
* It has not been tested with any other configurations!
* Inspired by: https://github.com/AlexMeah/grunt-zip-directories
*/
var async = require('async');
var done = this.async();
var archiver = require('archiver');
var fs = require('fs-extra');
var path = require('path');
var os = require('os');
process.setMaxListeners(0);
var options = this.options({
extension: '.zip',
deleteFolder: false
});
function begin(file, callback) {
var folders = file.src.toString().split(',');
var numZipFilesToCreate = folders.length;
folders.forEach(function (value) {
var folder = value;
var output = fs.createWriteStream(file.dest + "/" + folder + options.extension);
var archive = archiver('zip');
grunt.log.debug('Zipping ' + folder + " to " + file.dest + "/" + folder + options.extension);
output.on('close', function() {
if (options.deleteFolder) {
var path = file.dest + "/" + folder + "/.";
grunt.log.debug("Removing: " + path);
fs.removeSync(path, function (error) {
if (error) {
grunt.log.error("Failed to delete folder '" + folder + "': " + error);
}
grunt.log.debug("Deleted folder '" + folder);
});
}
if (--numZipFilesToCreate === 0) {
callback();
}
});
archive.on('error', function(err) {
throw err;
});
archive.pipe(output);
grunt.log.debug(file.cwd + ' ' + folder);
archive.glob('**', {
cwd: file.cwd + '/' + folder,
}, {});
archive.finalize(function(err) {
if (err) {
throw err;
}
});
});
}
if (!this.filesSrc) {
grunt.fail.fatal('No files found!');
}
// Iterate over all specified file groups.
async.eachLimit(this.files, os.cpus().length, begin, function (err) {
if (err) { return console.log(err); }
grunt.log.ok('Zipping complete');
done();
});
});
/*
* BUILD TARGETS
*/
grunt.registerTask('build', [
'clean:artifacts',
'jshint:src',
'shell:lightning-lint',
'todo',
'package_folders:staticResources'
]);
grunt.registerTask('push', [
'build',
'prompt:sfdcAlias',
'shell:force-push'
]);
grunt.registerTask('pull', [
'prompt:sfdcAlias',
'shell:force-pull'
]);
grunt.registerTask('test', [
'push',
'shell:force-test'
]);
grunt.registerTask('test-deploy', "Test deployment of all metadata files to a regular Salesforce org; available option: --ignore-tests", function() {
grunt.task.run([
'build',
'prompt:sfdcAlias',
'shell:force-convert-source',
]);
if (grunt.option('ignore-tests')) {
grunt.task.run(['shell:force-check-deploy-ignore-tests']);
} else {
grunt.task.run(['shell:force-check-deploy']);
}
});
grunt.registerTask('deploy', "Deploy all metadata files to a regular Salesforce org; available option: --ignore-tests", function() {
grunt.task.run([
'build',
'prompt:sfdcAlias',
'shell:force-convert-source',
]);
if (grunt.option('ignore-tests')) {
grunt.task.run(['shell:force-deploy-ignore-tests']);
} else {
grunt.task.run(['shell:force-deploy']);
}
});
// Setup default task that runs when you just run 'grunt'
grunt.registerTask('default', ['test']);
};
@echo off
:: Place file in the root folder of your SFDX project
IF NOT EXIST Gruntfile.js (
echo Please make sure to run this script in your DX root folder.
exit \B 1
)
SET /P SFALIAS="Your Salesforce DX Alias? "
echo Alright, let's create your scratch org with the alias "%SFALIAS%".
echo Before we begin, let's make sure your environment is ready.
call npm install
echo Ok, now it is time to create the scratch org.
sfdx force:org:create -s -f config\project-scratch-def.json -a %SFALIAS% -d 14
sfdx force:org:open -u %SFALIAS%
echo Please turn on Omni in the settings and hit enter when done...
pause
:pushMetadata
echo Let's push the metadata...
call grunt push
:end
echo That's it, you are ready to go :)
@j-fischer
Copy link
Author

And here are the dev dependencies for the Gruntfile, they might be a bit outdated:

"devDependencies": { "archiver": "^2.0.3", "async": "^2.0.1", "extract-zip": "^1.6.5", "fs-extra": "^4.0.1", "grunt": "^1.0.1", "grunt-batch": "^0.2.4", "grunt-contrib-clean": "^1.0.0", "grunt-contrib-copy": "^1.0.0", "grunt-contrib-jshint": "^1.0.0", "grunt-jslint": "1.1.15", "grunt-prompt": "^1.3.3", "grunt-shell": "^2.1.0", "grunt-todo": "^0.5.0", "jit-grunt": "^0.10.0", "jshint-stylish": "^2.2.0", "time-grunt-win": "^1.0.0" }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment