@vamship/build-utils 1.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2019] [Vamshi K Ponnapalli]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @vamship/grunt-utils
2
+
3
+ _Library of modules that are designed to construct an opinionated dev/build
4
+ toolchain for Javascript and Typescript projects._
5
+
6
+ > This library was originally intended for internal consumption, though the
7
+ > functionality provided by this library is fairly generic.
8
+
9
+ ## API Documentation
10
+
11
+ API documentation can be found [here](https://vamship.github.io/build-utils).
12
+
13
+ ## Motivation
14
+
15
+ In addition to writing code (and tests!), every project brings with it a common
16
+ set of tasks that comprise a _development workflow_ for the project. This
17
+ workflow includes common activities such as linting, formatting files, testing,
18
+ building, packaging, etc.
19
+
20
+ Having consistent way of performing these tasks makes it easier to switch from
21
+ one project to another, because all common tasks will be identical for a given
22
+ class of project (nodejs library, API server, etc.).
23
+
24
+ In order to ensure this consistency, a common task automation framework (Gulp)
25
+ is used, combined with a consistent configuration and development tool set for
26
+ that framework.
27
+
28
+ This library exports modules and classes that enable the creation of Gulpfiles,
29
+ ensuring that they can be ported from project to project with no changes.
30
+
31
+ All project specific parameters can be declared within a `buildMetdata` property
32
+ in package.json.
33
+
34
+ ## Installation
35
+
36
+ This library can be installed using npm:
37
+
38
+ ```
39
+ npm install @vamship/build-utils
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ This library is intended to be used with a Gulpfile that imports the necessary
45
+ tasks for the build system. The `examples` directory has a sample Gulpfile that
46
+ can be used for any project.
47
+
48
+ ### Environment Variables
49
+
50
+ Setting certain environment variables can alter the behavior of different build
51
+ tasks. The environment variables and their effects are listed below:
52
+
53
+ `BUILD_EXPORT_DOCKER_IMAGE`: When set to `true`, packaging a docker enabled
54
+ project will result in the creation of a tar file called `image-<key>.tar`
55
+ (using `docker save ...`) under the dist directory.
56
+
57
+ `BUILD_DOCKER_REPO`: This environment variable can be used to override the
58
+ docker repository name during package/publish operations.
59
+
60
+ ### Configuring package.json
61
+
62
+ The build system derives its configuration from buildMetadata that is explicitly
63
+ passed to the the project object via the Gulpfile, or by configuring settings
64
+ in the package.json file. We **strongly recommend** the use of package.json to
65
+ configure the build system.
66
+
67
+ Build metadata is identified in `package.json` via a property named
68
+ `buildMetadata`, which is an object that supports the following fields:
69
+
70
+ ```json
71
+ {
72
+ "projectType": "lib|cli|api|aws-microservice|container",
73
+ "language": "ts|js",
74
+ "requiredEnv": [ "...", "..." ],
75
+ "aws": {
76
+ "stacks" {
77
+ "stack-key": "stack-name",
78
+ ...
79
+ }
80
+ },
81
+ "docker": {
82
+ "x86": {
83
+ "repo": "...",
84
+ "buildFile": "Dockerfile"
85
+ "buildArgs": {
86
+ "arg-name": "__ENV__|<value>"
87
+ },
88
+ "isDefault": true,
89
+ },
90
+ "arm64": {
91
+ "repo": "...",
92
+ "buildFile": "Dockerfile.arm64"
93
+ "buildArgs": {
94
+ "arg-name": "__ENV__|<value>"
95
+ }
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ Note that all properties are not required for all types of projects. Refer to
102
+ the package.json files in the `examples` directory to get an idea of typical
103
+ configuration for different project types.
104
+
105
+ #### Upgrading to v0.3x
106
+
107
+ Starting from version 0.3, the docker build configuration supports multiple
108
+ targets, meaning that the application may be used to generate different docker
109
+ images, typically intended for different processor architectures. While the
110
+ changes are backwards compatible with 0.2.x, a deprecation warning will be
111
+ posted if the old style configuration is specified.
112
+
113
+ In order to upgrade to v 0.3 and above, the docker section should be updated
114
+ from
115
+
116
+ ```
117
+ "docker": {
118
+ "repo": "...",
119
+ "registry": "Dockerfile"
120
+ "buildArgs": {
121
+ "arg-name": "__ENV__|<value>"
122
+ },
123
+ }
124
+ ```
125
+
126
+ to:
127
+
128
+ ```
129
+ "docker": {
130
+ "default": {
131
+ "repo": "...",
132
+ "buildFile": "Dockerfile"
133
+ "buildArgs": {
134
+ "arg-name": "__ENV__|<value>"
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ The basic change is that the build configuration is specified as the value of a
141
+ build target key.
142
+
143
+ Note that the `docker.registry` parameter is no longer supported in the new
144
+ configuration format.
145
+
146
+ #### Properties:
147
+
148
+ `projectType`: Identifies the project type, which in turn determines the build
149
+ tasks generated by the system.
150
+
151
+ `language`: The project language - javascript or typescript.
152
+
153
+ `requiredEnv`: A list of environment variables that must be defined prior to some
154
+ tasks, such as publishing AWS projects, packaging docker images, publishing
155
+ private npm repositories, etc. The build system only checks for the existinence
156
+ of these variables, but does not care about their values.
157
+
158
+ `aws`: This object must be specified for aws microservice projects.
159
+ `aws.stacks`: This sub object defines a list of cloud formation stacks published
160
+ by the project. The keys represent the names that will be used for the gulp
161
+ tasks, and the values are the names of the cloud formation stacks.
162
+
163
+ `docker`: This object must be sepcified for projects that result in docker
164
+ images. This could apply to multiple project types including `cli`, `api` and
165
+ `container`. The docker configuration can specify multiple targets with
166
+ different docker files and build arguments. Each target has a name and a
167
+ corresponding set of configuration options. The name of the target can be any
168
+ string, except that a target named "default" is treated as the default packaging
169
+ target.
170
+
171
+ Each target can have the following properties:
172
+
173
+ `[target].repo`: A fully qualified repo name to be used to publish docker images.
174
+ `[target].buildFile`: The name of the docker file to use for the build. If
175
+ omitted, will default to "Dockerfile"
176
+ `[target].buildArgs`: This is a map of build arguments that will be passed to
177
+ docker at build time. The keys are the build argument names, and the values are
178
+ the argument values. A special value `__ENV__` indicates that the actual value
179
+ of the build argument must be extracted from the environment.
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@vamship/build-utils",
3
+ "version": "1.0.0-0",
4
+ "description": "Utility library for build tooling",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "clean": "rm -rf .nyc_output coverage",
8
+ "monitor": "nodemon --exec npm run test",
9
+ "test": "nyc mocha -R spec --recursive test/unit/ && nyc report --reporter=html",
10
+ "lint": "eslint src/**/*.js test/**/*.js",
11
+ "format": "prettier --write \"{{src,test}/**/*.js,README.md}\"",
12
+ "docs": "jsdoc --readme README.md --package package.json --template node_modules/docdash --destination docs --recurse src",
13
+ "all": "npm run format && npm run lint && npm run test && npm run clean"
14
+ },
15
+ "files": [
16
+ "package.json",
17
+ "LICENSE",
18
+ "README.md",
19
+ "src/**/*"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/vamship/build-utils.git"
24
+ },
25
+ "keywords": [
26
+ "gulp",
27
+ "build",
28
+ "test",
29
+ "utilities"
30
+ ],
31
+ "author": "Vamshi K Ponnapalli <vamshi.ponnapalli@gmail.com>",
32
+ "contributors": [
33
+ {
34
+ "name": "Onaje Baxley",
35
+ "email": "onaje.baxley@gmail.com"
36
+ }
37
+ ],
38
+ "license": "MIT",
39
+ "bugs": {
40
+ "url": "https://github.com/vamship/build-utils/issues"
41
+ },
42
+ "homepage": "https://github.com/vamship/build-utils#readme",
43
+ "devDependencies": {
44
+ "chai": "^4.3.4",
45
+ "chai-as-promised": "^7.1.1",
46
+ "eslint": "^7.32.0",
47
+ "gulp": "^4.0.2",
48
+ "gulp-eslint": "^6.0.0",
49
+ "gulp-jsdoc3": "^3.0.0",
50
+ "gulp-prettier": "^4.0.0",
51
+ "gulp-typedoc": "^3.0.1",
52
+ "gulp-typescript": "^5.0.1",
53
+ "gulp-zip": "^5.1.0",
54
+ "jsdoc": "^3.6.7",
55
+ "mocha": "^9.1.2",
56
+ "nodemon": "^2.0.13",
57
+ "nyc": "^15.1.0",
58
+ "prettier": "^2.4.1",
59
+ "rewire": "^5.0.0",
60
+ "sinon": "^11.1.2",
61
+ "sinon-chai": "^3.7.0"
62
+ },
63
+ "dependencies": {
64
+ "camelcase": "^6.2.0",
65
+ "delete": "^1.1.0",
66
+ "docdash": "^1.2.0",
67
+ "dotenv": "^10.0.0",
68
+ "dotenv-expand": "^5.1.0",
69
+ "execa": "^5.1.1",
70
+ "fancy-log": "^1.3.3",
71
+ "mkdirp": "^1.0.4",
72
+ "semver": "^7.3.5"
73
+ },
74
+ "peerDependencies": {
75
+ "@typescript-eslint/eslint-plugin": ">= ^4.25.0",
76
+ "@typescript-eslint/parser": ">= ^4.25.0",
77
+ "gulp": ">= ^4.0.2",
78
+ "gulp-eslint": ">= ^6.0.0",
79
+ "gulp-jsdoc3": ">= ^3.0.0",
80
+ "gulp-prettier": ">= ^4.0.0",
81
+ "gulp-typedoc": ">= ^3.0.1",
82
+ "gulp-typescript": ">= ^5.0.1",
83
+ "gulp-zip": ">= ^5.1.0",
84
+ "mocha": ">= ^9.1.2",
85
+ "nyc": ">= ^15.1.0",
86
+ "prettier": ">= ^2.4.1"
87
+ },
88
+ "optionalDependencies": {
89
+ "typedoc": ">= ^0.22.5",
90
+ "typescript": ">= ^4.4.4"
91
+ }
92
+ }
@@ -0,0 +1,234 @@
1
+ 'use strict';
2
+
3
+ const _path = require('path');
4
+
5
+ const _sepRegexp = new RegExp(_path.sep.replace(/\\/g, '\\\\'), 'g');
6
+
7
+ /**
8
+ * Abstract representation of a directory, with methods for traversal and
9
+ * glob pattern generation.
10
+ */
11
+ class Directory {
12
+ /**
13
+ * @param {String} path The path represented by this directory.
14
+ */
15
+ constructor(path) {
16
+ if (typeof path !== 'string') {
17
+ throw new Error('Invalid path specified (arg #1)');
18
+ }
19
+
20
+ let relativePath = path.replace(process.cwd(), '');
21
+ this._name = _path.basename(_path.resolve(path));
22
+ this._path = _path.join(relativePath, `.${_path.sep}`);
23
+
24
+ this._absolutePath = _path.join(_path.resolve(path), _path.sep);
25
+ this._globPath = this._absolutePath.replace(_sepRegexp, '/');
26
+
27
+ this._children = [];
28
+ }
29
+
30
+ /**
31
+ * Creates a folder tree based on an object that describes the tree
32
+ * structure.
33
+ *
34
+ * @param {String} rootPath A string that represents the path to the root
35
+ * directory of the tree.
36
+ * @param {Object} tree An object representation of the tree structure.
37
+ * @return {Directory} A directory object that represents the root of
38
+ * the tree.
39
+ */
40
+ static createTree(rootPath, tree) {
41
+ if (typeof rootPath !== 'string') {
42
+ throw new Error('Invalid rootPath specified (arg #1)');
43
+ }
44
+ if (!tree || tree instanceof Array || typeof tree !== 'object') {
45
+ throw new Error('Invalid tree specified (arg #2)');
46
+ }
47
+
48
+ function createRecursive(parent, tree) {
49
+ if (typeof parent === 'string') {
50
+ parent = new Directory(parent);
51
+ }
52
+
53
+ if (tree && !(tree instanceof Array) && typeof tree === 'object') {
54
+ for (let dirName in tree) {
55
+ let child = parent.addChild(dirName);
56
+ createRecursive(child, tree[dirName]);
57
+ }
58
+ }
59
+ return parent;
60
+ }
61
+
62
+ return createRecursive(rootPath, tree);
63
+ }
64
+
65
+ /**
66
+ * Traverses a directory tree, invoking the callback function at each level
67
+ * of the tree.
68
+ *
69
+ * @param {Directory} root The root level of the tree to traverse.
70
+ * @param {Function} callback The callback function that is invoked as each
71
+ * directory is traversed.
72
+ */
73
+ static traverseTree(root, callback) {
74
+ if (!(root instanceof Directory)) {
75
+ throw new Error('Invalid root directory specified (arg #1)');
76
+ }
77
+ if (typeof callback !== 'function') {
78
+ throw new Error('Invalid callback function specified (arg #1)');
79
+ }
80
+ function traverseRecursive(parent, level) {
81
+ callback(parent, level);
82
+ level++;
83
+ parent.getChildren().forEach((child) => {
84
+ traverseRecursive(child, level);
85
+ });
86
+ }
87
+
88
+ return traverseRecursive(root, 0);
89
+ }
90
+
91
+ /**
92
+ * Returns the name of the directory.
93
+ *
94
+ * @type {String}
95
+ */
96
+ get name() {
97
+ return this._name;
98
+ }
99
+
100
+ /**
101
+ * Returns the relative path to this directory.
102
+ *
103
+ * @return {String}
104
+ */
105
+ get path() {
106
+ return this._path;
107
+ }
108
+
109
+ /**
110
+ * Returns the absolute path to this directory.
111
+ *
112
+ * @type {String}
113
+ */
114
+ get absolutePath() {
115
+ return this._absolutePath;
116
+ }
117
+
118
+ /**
119
+ * Returns the glob path to the file.
120
+ */
121
+ get globPath() {
122
+ return this._globPath;
123
+ }
124
+
125
+ /**
126
+ * Adds a child directory object to the current directory.
127
+ *
128
+ * @param {String} name Name of the child directory.
129
+ */
130
+ addChild(name) {
131
+ if (typeof name !== 'string' || name.length <= 0) {
132
+ throw new Error('Invalid directory name specified (arg #1)');
133
+ }
134
+ if (name.match(/[\\/:]/)) {
135
+ throw new Error(
136
+ 'Directory name cannot include path separators (:, \\ or /)'
137
+ );
138
+ }
139
+ const child = new Directory(_path.join(this.path, name));
140
+ this._children.push(child);
141
+
142
+ return child;
143
+ }
144
+
145
+ /**
146
+ * Retrieves a child directory object by recursively searching through the
147
+ * current directory's child tree.
148
+ *
149
+ * @param {String} path The relative path to the child directory, with
150
+ * each path element separated by "/".
151
+ * @return {Directory} A directory reference for the specified child. If
152
+ * a child is not found at the specified path, an error will be
153
+ * thrown.
154
+ */
155
+ getChild(path) {
156
+ if (typeof path !== 'string' || path.length <= 0) {
157
+ throw new Error('Invalid child path specified (arg #1)');
158
+ }
159
+ const tokens = path.split('/');
160
+ const child = tokens.reduce((result, name) => {
161
+ if (!result) {
162
+ return result;
163
+ }
164
+ const children = result.getChildren();
165
+ return children.find((child) => child.name === name);
166
+ }, this);
167
+
168
+ if (!child) {
169
+ throw new Error(`Child not found at path: [${path}]`);
170
+ }
171
+ return child;
172
+ }
173
+
174
+ /**
175
+ * Returns an array containing all first level children of the current
176
+ * directory.
177
+ *
178
+ * @return {Directory[]} An array of first level children for the directory.
179
+ */
180
+ getChildren() {
181
+ return this._children.slice();
182
+ }
183
+
184
+ /**
185
+ * Returns the path to a file within the current directory. This file
186
+ * does not have to actually exist on the file system, and can also be the
187
+ * name of a directory.
188
+ *
189
+ * @param {String} fileName The name of the file.
190
+ * @return {String} The path to the file including the current directory
191
+ * path.
192
+ */
193
+ getFilePath(fileName) {
194
+ if (typeof fileName !== 'string') {
195
+ fileName = '';
196
+ }
197
+ return _path.join(this.absolutePath, fileName);
198
+ }
199
+
200
+ /**
201
+ * Returns a glob path to a file within the current directory. This file
202
+ * does not have to actually exist on the file system, and can also be the
203
+ * name of a directory.
204
+ *
205
+ * @param {String} fileName The name of the file.
206
+ * @return {String} The path to the file including the current directory
207
+ * path.
208
+ */
209
+ getFileGlob(fileName) {
210
+ if (typeof fileName !== 'string') {
211
+ fileName = '';
212
+ }
213
+ return _path.join(this.absolutePath, fileName).replace(_sepRegexp, '/');
214
+ }
215
+
216
+ /**
217
+ * Gets a string glob that can be used to match all folders/files in the
218
+ * current folder and all sub folders, optionally filtered by file
219
+ * extension.
220
+ *
221
+ * @param {String} [extension] An optional extension to use when generating
222
+ * a globbing pattern.
223
+ */
224
+ getAllFilesGlob(extension) {
225
+ if (typeof extension !== 'string') {
226
+ extension = '*';
227
+ } else {
228
+ extension = `*.${extension}`;
229
+ }
230
+ return `${this.globPath}**/${extension}`;
231
+ }
232
+ }
233
+
234
+ module.exports = Directory;
package/src/index.js ADDED
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Utility library that can be used to create development tooling.
5
+ */
6
+ module.exports = {
7
+ /**
8
+ * A class that represents a directory on the file system.
9
+ */
10
+ Directory: require('./directory'),
11
+
12
+ /**
13
+ * Represents a specific project configuration.
14
+ */
15
+ Project: require('./project'),
16
+
17
+ /**
18
+ * A collection of task builder functions that can be used to generate
19
+ * commonly used gulp files for projects.
20
+ */
21
+ taskBuilders: require('./task-builders'),
22
+ };