Skip to content

Commit

Permalink
Pack to ./artifacts, implemented pack:deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
andersnm committed Apr 21, 2019
1 parent c982a61 commit 9dfafed
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 36 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Monorepo for blerf, a monorepo tool.

See [packages/blerf](packages/blerf)

[![Build status](https://ci.appveyor.com/api/projects/status/ivy1wa5f6dsmdmym?svg=true)](https://ci.appveyor.com/project/andersnm/blerf)

## Building the source code

Check out and bootstrap the monorepo:
Expand Down
24 changes: 18 additions & 6 deletions packages/blerf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ Opinionated build tool for nodejs monorepos working alongside npm. Helps manage

## Commands

`blerf build`
### `blerf build`

In each directory under ./packages containing a package.json, first runs `npm install` if any of the top level dependencies are missing, and then executes any build steps. A build step is skipped if there are no changes in the filesystem based on the glob patterns in `srcPath` and `outPath`. The code in `script` is spawned similar to npm scripts, where the PATH environment variable is modified to include node_modules/.bin.
Installs dependencies and executes any build steps in each directory under ./packages containing a package.json.

Dependencies are skipped if all top level dependencies are present in a project's node_modules folder. Detects and recovers from certain types of corruption in package-lock.json. Uses `npm install` under the hood.

Build steps are specified in package.json. Build steps are skipped if there are no changes in the filesystem based on the glob patterns in `srcPath` and `outPath`. The code in `script` is spawned similar to npm scripts, where the PATH environment variable is modified to include node_modules/.bin.

Example blerf section in package.json with a build step for TypeScript:

Expand All @@ -32,11 +36,19 @@ Example blerf section in package.json with a build step for TypeScript:

The values for outPath and srcPath must match the tsconfig.json compiler options.

`blerf pack:publish`
### `blerf pack:publish`

Creates tarballs for each directory under ./packages containing a package.json. The output *.tgz files are located in ./artifacts/publish and are suitable for publishing to a registry.

Uses `npm pack` under the hood. The final tarballs will have fixed project references pointing to their corresponding version number with a ^-modifier.

### `blerf pack:deploy`

Creates standalone tarballs for each directory under ./packages containing a package.json. The output *.tgz files are located in ./artifacts/deploy and are suitable for application deployments.

Executes `npm pack` in each directory under ./packages containing a package.json and fixes up any project references in the tarballs. This extracts each tarball to a temp directory, changes any `file:` based dependencies in package.json to their corresponding version, updates the tarball and cleans up.
Uses `npm pack` and `npm install` under the hood. The final tarballs will have all dependencies included.

`blerf test`
### `blerf test`

Executes `npm run test` in each directory under ./packages containing a package.json having a test script. If `coverageFrom` is set to a valid path, code coverage information will be collected and reported using Node's built-in `NODE_V8_COVERAGE` coverage facilities, with source map support. The built-in code coverage requires Node 10.12 or newer, and a test runner which does not transform/wrap the source code.

Expand All @@ -48,7 +60,7 @@ Example blerf section in package.json enabling coverage on files in a sibling pr
}
```

`blerf run [xxx]`
### `blerf run [xxx]`

Executes `npm run [xxx]` in each directory under ./packages containing a package.json having a corresponding script.

Expand Down
2 changes: 1 addition & 1 deletion packages/blerf/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "blerf",
"version": "0.0.2",
"version": "0.0.3",
"description": "Blerf monorepo/solution/project management tool. Handle dependencies and run build tasks when source files change. Pack for publish, pack for deployment.",
"author": "andersnm",
"license": "MIT",
Expand Down
1 change: 0 additions & 1 deletion packages/blerf/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ export class BuildEnumerator extends PackageEnumerator {
private hasAllDependencies(packageJson: any, dependencyNames: string[]) {
for (const dependencyName of dependencyNames) {
if (!this.hasDependency(packageJson, dependencyName)) {
console.log("MISSING" + dependencyName)
return false;
}
}
Expand Down
44 changes: 44 additions & 0 deletions packages/blerf/src/commands/bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import * as childProcess from 'child_process';
import { PackageEnumerator, PackagesType } from "../packageEnumerator";
const tar = require('tar')

export class BundleEnumerator extends PackageEnumerator {
private artifactPackPath: string;
private artifactDeployPath: string;

constructor(rootPath: string, artifactPackPath: string, artifactDeployPath: string) {
super(rootPath);
this.artifactPackPath = artifactPackPath;
this.artifactDeployPath = artifactDeployPath;
}

public async enumeratePackages(): Promise<void> {
await super.enumeratePackages();

// Remove artifacts/deploy-temp created by PackEnumerator
this.rimraf(this.artifactPackPath);
}

protected async processPackage(packagePath: string, packageJson: any, packages: PackagesType): Promise<void> {
console.log("blerf: bundling node_modules");

// NOTE: assuming file name of tarball; can also get it from the output of npm pack
const tempPath = fs.mkdtempSync(path.join(os.tmpdir(), "blerf-"));
const artifactPackTarPath = path.join(this.artifactPackPath, packageJson.name + "-" + packageJson.version + ".tgz");
const artifactTarPath = path.join(this.artifactDeployPath, packageJson.name + "-" + packageJson.version + ".tgz");

fs.mkdirSync(this.artifactDeployPath, { recursive: true });

try {
tar.extract({ file: artifactPackTarPath, cwd: tempPath, sync: true });
childProcess.execSync("npm install", {stdio: 'inherit', cwd: path.join(tempPath, "package") });

tar.create({ file: artifactTarPath, cwd: tempPath, gzip: true, sync: true, }, ["package"]);
} finally {
this.rimraf(tempPath);
}
}
}
40 changes: 30 additions & 10 deletions packages/blerf/src/commands/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@ const tar = require('tar')

export class PackEnumerator extends PackageEnumerator {
private isDeploy: boolean;
private artifactCleanPath: string;
private artifactPackPath: string;

constructor(rootPath: string, isDeploy: boolean) {
constructor(rootPath: string, artifactPath: string, artifactCleanPath: string, isDeploy: boolean) {
super(rootPath);
this.isDeploy = isDeploy;
this.artifactCleanPath = artifactCleanPath;
this.artifactPackPath = artifactPath;
}

public async enumeratePackages(): Promise<void> {
this.rimraf(this.artifactCleanPath);
await super.enumeratePackages();
}

protected async processPackage(packagePath: string, packageJson: any, packages: PackagesType): Promise<void> {
Expand All @@ -23,16 +32,24 @@ export class PackEnumerator extends PackageEnumerator {
const sourcePackageTarPath = path.join(packagePath, packageJson.name + "-" + packageJson.version + ".tgz");
const tempPath = fs.mkdtempSync(path.join(os.tmpdir(), "blerf-"));

const artifactPackTarPath = path.join(this.artifactPackPath, packageJson.name + "-" + packageJson.version + ".tgz");

fs.mkdirSync(this.artifactPackPath, { recursive: true });

try {
tar.extract({ file: sourcePackageTarPath, cwd: tempPath, sync: true });
this.patchPackageJson(packagePath, path.join(tempPath, "package", "package.json"), packages);
tar.create({ file: sourcePackageTarPath, cwd: tempPath, gzip: true, sync: true, }, ["package"]);
this.patchPackageJson(packagePath, path.join(tempPath, "package", "package.json"), path.resolve(this.artifactPackPath), packages);
if (this.isDeploy) {
fs.copyFileSync(path.join(packagePath, "package-lock.json"), path.join(tempPath, "package", "package-lock.json"));
}
tar.create({ file: artifactPackTarPath, cwd: tempPath, gzip: true, sync: true, }, ["package"]);
} finally {
fs.unlinkSync(sourcePackageTarPath);
this.rimraf(tempPath);
}
}

updateDependencyVersions(packagePath: string, packageDependencies: any, packages: PackagesType) {
updateDependencyVersions(packagePath: string, artifactPackFullPath: string, packageDependencies: any, packages: PackagesType) {
if (!packageDependencies) {
return;
}
Expand All @@ -46,9 +63,9 @@ export class PackEnumerator extends PackageEnumerator {
const dependencyPackageInfo = packages[dependencyName];
if (dependencyPackageInfo) {
if (this.isDeploy) {
packageDependencies[dependencyName] = dependencyPackageInfo.packageJson.name + "-" + dependencyPackageInfo.packageJson.version + ".tgz";
packageDependencies[dependencyName] = path.join(artifactPackFullPath, dependencyPackageInfo.packageJson.name + "-" + dependencyPackageInfo.packageJson.version + ".tgz");
} else {
packageDependencies[dependencyName] = dependencyPackageInfo.packageJson.version;
packageDependencies[dependencyName] = "^" + dependencyPackageInfo.packageJson.version;
}
} else {
// TODO: possibly noop instead?
Expand All @@ -57,12 +74,15 @@ export class PackEnumerator extends PackageEnumerator {
}
}

private patchPackageJson(packagePath: string, packageJsonPath: string, packages: PackagesType) {
private patchPackageJson(packagePath: string, packageJsonPath: string, artifactPackFullPath: string, packages: PackagesType) {
// Resolve all file:-based dependencies to explicit versions
const packageJson = this.readPackageJson(packageJsonPath);
this.updateDependencyVersions(packagePath, packageJson.dependencies, packages);
this.updateDependencyVersions(packagePath, packageJson.devDependencies, packages);
this.updateDependencyVersions(packagePath, artifactPackFullPath, packageJson.dependencies, packages);
this.updateDependencyVersions(packagePath, artifactPackFullPath, packageJson.devDependencies, packages);
// Remove stuff not needed in "binary" packge
delete packageJson.scripts;
delete packageJson.blerf;
delete packageJson.devDependencies;
fs.writeFileSync(packageJsonPath, stringifyPackage(packageJson), 'utf8');
}

}
44 changes: 26 additions & 18 deletions packages/blerf/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,32 @@ import { RunEnumerator } from './commands/run';
import { PackEnumerator } from './commands/pack';
import { BuildEnumerator } from './commands/build';
import { TestEnumerator } from './commands/test';
import { BundleEnumerator } from './commands/bundle';

const rootPath = "packages";

if (process.argv[2] === "run") {
const cmd = new RunEnumerator(rootPath, process.argv.slice(3));
cmd.enumeratePackages();
} else if (process.argv[2] === "pack:publish") {
const cmd = new PackEnumerator(rootPath, false);
cmd.enumeratePackages();
} else if (process.argv[2] === "pack:deploy") {
const cmd = new PackEnumerator(rootPath, true);
cmd.enumeratePackages();
} else if (process.argv[2] === "build") {
const cmd = new BuildEnumerator(rootPath);
cmd.enumeratePackages();
} else if (process.argv[2] === "test") {
const cmd = new TestEnumerator(rootPath);
cmd.enumeratePackages();
} else {
console.log("usage: blerf [run|install|pack|build|test]")
}
(async () => {

if (process.argv[2] === "run") {
const cmd = new RunEnumerator(rootPath, process.argv.slice(3));
await cmd.enumeratePackages();
} else if (process.argv[2] === "pack:publish") {
const cmd = new PackEnumerator(rootPath, "artifacts/publish", "artifacts/publish", false);
await cmd.enumeratePackages();
} else if (process.argv[2] === "pack:deploy") {
const pack = new PackEnumerator(rootPath, "artifacts/deploy-temp", "artifacts/deploy", true);
await pack.enumeratePackages();

const bundle = new BundleEnumerator(rootPath, "artifacts/deploy-temp", "artifacts/deploy");
await bundle.enumeratePackages();
} else if (process.argv[2] === "build") {
const cmd = new BuildEnumerator(rootPath);
await cmd.enumeratePackages();
} else if (process.argv[2] === "test") {
const cmd = new TestEnumerator(rootPath);
await cmd.enumeratePackages();
} else {
console.log("usage: blerf [run|install|pack|build|test]")
}

})();

0 comments on commit 9dfafed

Please sign in to comment.