@acdf/build
Version:
Build dependency for Adobe Campaign Developer Framework projects
243 lines (207 loc) • 7.36 kB
JavaScript
const { src, dest } = require("gulp");
const clean = require("gulp-clean");
const fs = require("fs");
const merge = require("merge-stream");
const path = require("path");
const zip = require("gulp-zip");
const resolve = (filepath) => path.resolve(process.cwd(), filepath);
const CLEAN_CONFIG = { read: false, allowEmpty: true };
const CONFIG_FILE = resolve("acdf.config.json")
const RELEASE_FILE = resolve("release.js")
const ENV_DIR = resolve("envs");
const PACKAGE_JSON = JSON.parse(fs.readFileSync(resolve("package.json"), "utf8"));
// Default configuration values
const DEFAULT_CONFIG = {
namespace: "acdf",
};
// Filename suffixes
const suffix = {
ACTIVITY: ".activity",
LIBRARY: ".library",
TYPOLOGY: ".typology",
ENVIRONMENT: ".env",
CONF: ".conf"
};
const CONFIG = (() => {
if (fs.existsSync(CONFIG_FILE)) {
const projectConfig = JSON.parse(fs.readFileSync(CONFIG_FILE));
return { ...DEFAULT_CONFIG, ...projectConfig };
}
return DEFAULT_CONFIG;
})();
/**
* Creates the globs to find the different types of script files in a given directory
*
* @param {string} directoryPath
* @returns a list of glob strings
*/
function createScriptGlobs(directoryPath) {
return [suffix.ACTIVITY, suffix.LIBRARY, suffix.TYPOLOGY].map((extension) => `${directoryPath}/**/*${extension}.js`);
}
/**
* Creates relative and absolute versions of all paths defined in the paths object. In the format:
* paths.<directory>.<type>.<name>
* Eg:
* paths.dist.absolute.MODULE_DIR
*
* @param {obj} paths
* @returns an object containing relative and absolute paths
*/
function constructPaths(paths) {
return Object.keys(paths).reduce((result, folder) => {
result[folder] = {
relative: {},
absolute: {}
};
Object.keys(paths[folder]).forEach(key => {
result[folder].relative[key] = `${folder}/${paths[folder][key]}`;
result[folder].absolute[key] = resolve(result[folder].relative[key])
})
return result
}, {})
}
// Useful paths
const paths = constructPaths({
src: {
CONF_DIR: "conf",
SCRIPTS_DIR: "js",
PACKAGES_DIR: "packages",
},
dist: {
CONF_DIR: "conf",
COMPILED_DIR: "compiled",
COMPRESSED_DIR: "compressed",
MODULE_DIR: "modules",
PACKAGE_DIR: "packages",
STAGING_DIR: "staging",
WIZARD_DIR: "wizards",
}
});
/**
* Recursively builds a map where, for each entry, the key is the script name and the entry is the path
* of the corresponding CommonJS module file.
*
* @param {string} filepath
* @param {string} map
* @returns
*/
function buildScriptMap(filepath, map) {
const addScript = (filename, filepath) => {
const key = `${CONFIG.namespace}:${filename}`;
if (map[key]) {
throw `Attempted to add script with identifier '${key}' but such a script already exists at '${map[key]}'. Each script must have a unique identifier.`;
} else {
map[key] = filepath;
}
};
if (!map) {
map = {};
}
if (!fs.existsSync(filepath)) {
return map;
}
const filename = path.parse(filepath).base;
const isScript = [suffix.LIBRARY, suffix.ACTIVITY, suffix.TYPOLOGY].some((suffix) => filename.includes(suffix));
if (fs.lstatSync(filepath).isDirectory()) {
if (isScript) {
addScript(filename, filepath);
return map;
}
fs.readdirSync(filepath).forEach((child) => buildScriptMap(path.resolve(filepath, child), map));
} else if (isScript) {
addScript(filename, filepath);
}
return map;
}
/**
* Creates an array containing the properties exported in each environment file.
*
* @returns an array of environments
*/
function getEnvs() {
if (!fs.existsSync(ENV_DIR)) {
throw `Cannot build project. Please create at least one environment file in ${ENV_DIR}`
}
return fs
// Find env files
.readdirSync(ENV_DIR)
.filter((envFilename) => fs.statSync(path.resolve(ENV_DIR, envFilename)).isFile() && envFilename.includes(suffix.ENVIRONMENT))
// For each env file, save a reference to the environment
.reduce((envs, envFilename) => {
const envName = envFilename.replace(suffix.ENVIRONMENT + ".js", "");
const env = require(path.resolve(ENV_DIR, envFilename));
// Copy the global properties into each installation object
const envProperties = env.properties || {};
env.installations.forEach(installation => {
installation.properties = installation.properties
? { ...envProperties, ...installation.properties }
: envProperties
})
envs.push({
name: envName,
...env
})
return envs
}, [])
}
/**
* Finds the release with the installationName provided. Throws an error if no such release is present
* in the release.js file.
*
* @param {string} installationName the name of the installation to create a release for
* @returns the release
*/
function getRelease(installationName) {
const installation = require(resolve("release.js")).installations.find(installation => installationName === installation.name)
if (!installation) {
throw `Could not find any installation by the name ${installationName} in the 'release.js' file.`
}
return installation;
}
module.exports = {
// Objects
paths: paths,
suffix: suffix,
CLEAN_CONFIG: CLEAN_CONFIG,
CONFIG: CONFIG,
PACKAGE_JSON: PACKAGE_JSON,
REGEX_LOAD_LIBRARY: /^ *loadLibrary\(["'](.*)["']\);?$/gm,
GLOB_COMPILED_SCRIPTS: createScriptGlobs(paths.dist.absolute.COMPILED_DIR),
GLOB_MODULE_SCRIPTS: createScriptGlobs(paths.dist.absolute.MODULE_DIR),
GLOB_STAGING_SCRIPTS: createScriptGlobs(paths.dist.absolute.STAGING_DIR),
GLOB_STAGING_PACKAGES: `${paths.dist.absolute.STAGING_DIR}/packages/**/*.xml`,
GLOB_PACKAGE_PACKAGES: `dist/packages/**/*.xml`,
GLOB_SRC_SCRIPTS: createScriptGlobs("src"),
// Functions
resolve: resolve,
buildScriptMap: buildScriptMap,
getEnvs: getEnvs,
getRelease: getRelease,
cleanDest: function () {
return merge(src("dist", CLEAN_CONFIG).pipe(clean()), src("docs", CLEAN_CONFIG).pipe(clean()));
},
clearStage: () => {
return src(paths.dist.absolute.STAGING_DIR, CLEAN_CONFIG).pipe(clean());
},
/**
* Creates a deployable zip archive for each application-environment subdirectory of the directory
* provided, containing files that subdirectory.
*
* @param {string} directory
* @returns a gulp stream
*/
createArtifact: (directory) => {
// Skip if directory does not exist
if (!fs.existsSync(directory)) {
return src(".");
}
const streams = fs
.readdirSync(directory)
.map(subdirectory => {
return src(`${path.resolve(directory, subdirectory)}/**/*`)
.pipe(zip(`${PACKAGE_JSON.name}.${subdirectory}-${PACKAGE_JSON.version}.zip`))
.pipe(dest("dist"));
})
return merge(streams);
},
};