Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build script with repo package manifest and release ordering #3658

Merged
merged 3 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,44 @@
"rimraf": "^2.6.2",
"run-script-os": "^1.0.7",
"typescript": "~3.7.4"
},
"fluidBuild": {
"repoPackages": {
"client": [
{
"directory": "common"
},
{
"directory": "tools/generator-fluid"
}
],
"server": {
"required": [
{
"directory": "server/tinylicious"
}
],
"optional": [
{
"directory": "server",
"ignoredDirs": [
"routerlicious"
]
}
]
}
},
"serverPath": "server/routerlicious",
"releaseOrder": {
"preRepo": [
["@fluidframework/eslint-config-fluid", "@fluidframework/build-common"],
["@fluidframework/common-definitions"],
["@fluidframework/common-utils"]
],
"postRepo": [
["generator-fluid", "tinylicious"]
]
},
"generatorName": "generator-fluid"
}
}
62 changes: 41 additions & 21 deletions tools/build-tools/src/bumpVersion/bumpVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
import * as path from "path";
import { commonOptions, commonOptionString, parseOption } from "../common/commonOptions";
import { Timer } from "../common/timer";
import { getResolvedFluidRoot } from "../common/fluidUtils";
import { FluidRepoBase } from "../common/fluidRepoBase";
import { getResolvedFluidRoot, getPackageManifest } from "../common/fluidUtils";
import { FluidRepo, IPackageManifest } from "../common/fluidRepo";
import { MonoRepo, MonoRepoKind } from "../common/monoRepo";
import * as semver from "semver";
import { Package } from "../common/npmPackage";
import { logVerbose } from "../common/logging";
import { GitRepo, fatal, exec, execNoError } from "./utils";
import * as os from "os";
import { assert } from "console";

function printUsage() {
console.log(
Expand Down Expand Up @@ -46,8 +47,6 @@ let paramVersion: semver.SemVer | undefined;
let paramBumpName: string | undefined;
let paramBumpVersion: VersionChangeType | undefined;

const generatorFluidPackageName = "generator-fluid";

function parseNameVersion(arg: string | undefined) {
let name = arg;
let extra = false;
Expand Down Expand Up @@ -442,10 +441,11 @@ class ReferenceVersionBag extends VersionBag {

class BumpVersion {
private readonly timer: Timer;
private readonly repo: FluidRepoBase;
private readonly repo: FluidRepo;
private readonly fullPackageMap: Map<string, Package>;
private readonly generatorPackage: Package;
private readonly templatePackage: Package;
private readonly packageManifest: IPackageManifest;
private readonly newBranches: string[] = [];
private readonly newTags: string[] = [];

Expand All @@ -457,14 +457,16 @@ class BumpVersion {
this.timer = new Timer(commonOptions.timer);

// Load the package
this.repo = new FluidRepoBase(this.gitRepo.resolvedRoot, false);
this.repo = new FluidRepo(this.gitRepo.resolvedRoot, false);
this.timer.time("Package scan completed");

this.fullPackageMap = this.repo.createPackageMap();
this.packageManifest = getPackageManifest(this.repo.resolvedRoot);

// TODO: Is there a way to generate this automatically?
const generatorPackage = this.fullPackageMap.get(generatorFluidPackageName);
if (!generatorPackage) { fatal(`Unable to find ${generatorFluidPackageName} package`) };
if (!this.packageManifest.generatorName) { fatal(`Unable to find generator package name in package.json`)}
const generatorPackage = this.fullPackageMap.get(this.packageManifest.generatorName);
if (!generatorPackage) { fatal(`Unable to find ${this.packageManifest.generatorName} package`) };
this.generatorPackage = generatorPackage;
this.templatePackage = new Package(path.join(generatorPackage.directory, "app", "templates", "package.json"));
}
Expand Down Expand Up @@ -563,7 +565,8 @@ class BumpVersion {
if (releaseName === MonoRepoKind[MonoRepoKind.Client]) {
processMonoRepo(this.repo.clientMonoRepo);
} else if (releaseName === MonoRepoKind[MonoRepoKind.Server]) {
processMonoRepo(this.repo.serverMonoRepo);
assert(this.repo.serverMonoRepo, "Attempted to collect server info on a Fluid repo with no server directory");
processMonoRepo(this.repo.serverMonoRepo!);
} else {
const pkg = this.fullPackageMap.get(releaseName);
if (!pkg) {
Expand Down Expand Up @@ -648,7 +651,8 @@ class BumpVersion {
if (name === MonoRepoKind[MonoRepoKind.Client]) {
await processMonoRepo(this.repo.clientMonoRepo);
} else if (name === MonoRepoKind[MonoRepoKind.Server]) {
await processMonoRepo(this.repo.serverMonoRepo);
assert(this.repo.serverMonoRepo, "Attempted show server versions on a Fluid repo with no server directory");
await processMonoRepo(this.repo.serverMonoRepo!);
} else {
pkg = this.fullPackageMap.get(name);
if (!pkg) {
Expand Down Expand Up @@ -679,7 +683,8 @@ class BumpVersion {

if (serverNeedBump) {
console.log(" Bumping server version");
await bumpMonoRepo(this.repo.serverMonoRepo);
assert(this.repo.serverMonoRepo, "Attempted server version bump on a Fluid repo with no server directory");
await bumpMonoRepo(this.repo.serverMonoRepo!);
}

for (const pkg of packageNeedBump) {
Expand Down Expand Up @@ -1006,13 +1011,13 @@ class BumpVersion {
}

/**
* Create release branch based on the repo state, bump minor version immediately
* Create release branch based on the repo state, bump minor version immediately
* and push it to `main` and the new release branch to remote
*/
public async createReleaseBranch() {
// Create release branch based on client version
const releaseName = MonoRepoKind[MonoRepoKind.Client];

const depVersions = await this.collectBumpInfo(releaseName);
const releaseVersion = depVersions.repoVersions.get(releaseName);
if (!releaseVersion) {
Expand Down Expand Up @@ -1115,13 +1120,27 @@ class BumpVersion {
await this.createBranch(pendingReleaseBranch);
}

// TODO: Don't hard code order
await this.releasePackage(depVersions, ["@fluidframework/eslint-config-fluid", "@fluidframework/build-common"]);
await this.releasePackage(depVersions, ["@fluidframework/common-definitions"]);
await this.releasePackage(depVersions, ["@fluidframework/common-utils"]);
await this.releaseMonoRepo(depVersions, this.repo.serverMonoRepo);
const preRepoPromises: Promise<void>[] = [];
if (this.packageManifest.releaseOrder?.preRepo !== undefined) {
this.packageManifest.releaseOrder.preRepo.forEach(async packages =>
preRepoPromises.push(this.releasePackage(depVersions, packages))
);
}
await Promise.all(preRepoPromises);

if (this.repo.serverMonoRepo) {
await this.releaseMonoRepo(depVersions, this.repo.serverMonoRepo);
}

await this.releaseMonoRepo(depVersions, this.repo.clientMonoRepo);
await this.releasePackage(depVersions, [generatorFluidPackageName, "tinylicious"]);

const postRepoPromises: Promise<void>[] = [];
if (this.packageManifest.releaseOrder?.postRepo !== undefined) {
this.packageManifest.releaseOrder.postRepo.forEach(async packages =>
postRepoPromises.push(this.releasePackage(depVersions, packages))
);
}
await Promise.all(postRepoPromises);

// ------------------------------------------------------------------------------------------------------------------
// Create the minor version bump for development in a temporary merge/<original branch> on top of the release commit
Expand Down Expand Up @@ -1173,7 +1192,8 @@ class BumpVersion {
}
} else if (name === MonoRepoKind[MonoRepoKind.Server]) {
serverNeedBump = true;
const ret = await this.repo.serverMonoRepo.install();
assert(this.repo.serverMonoRepo, "Attempted to bump server version on a Fluid repo with no server directory");
const ret = await this.repo.serverMonoRepo!.install();
if (ret.error) {
fatal("Install failed");
}
Expand Down Expand Up @@ -1241,7 +1261,7 @@ class BumpVersion {
if (updateLockPackage.length !== 0) {
if (updateLock) {
// Fix package lock
if (!await FluidRepoBase.ensureInstalled(updateLockPackage, false)) {
if (!await FluidRepo.ensureInstalled(updateLockPackage, false)) {
fatal("Install Failed");
}
} else {
Expand Down
113 changes: 113 additions & 0 deletions tools/build-tools/src/common/fluidRepo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import * as path from "path";
import { Package, Packages } from "./npmPackage";
import { MonoRepo, MonoRepoKind } from "./monoRepo";
import { getPackageManifest } from "./fluidUtils";
import { assert } from "console";

export interface IPackageManifest {
repoPackages: {
client: IFluidRepoPackage[],
server: {
required: IFluidRepoPackage[],
optional?: IFluidRepoPackage[],
}
},
serverPath?: string,
releaseOrder?: {
preRepo?: string[][],
postRepo?: string[][]
},
generatorName?: string
}

export interface IFluidRepoPackage {
directory: string,
ignoredDirs?: string[]
}

export class FluidRepo {
public readonly clientMonoRepo: MonoRepo;
public readonly serverMonoRepo?: MonoRepo;

public readonly packages: Packages;
constructor(public readonly resolvedRoot: string, services: boolean) {
const packageManifest = getPackageManifest(resolvedRoot);
this.clientMonoRepo = new MonoRepo(MonoRepoKind.Client, this.resolvedRoot);
if (packageManifest.serverPath) {
this.serverMonoRepo = new MonoRepo(MonoRepoKind.Server, path.join(this.resolvedRoot, packageManifest.serverPath));
}

let additionalPackages: Package[] = [];

packageManifest.repoPackages.client.forEach((fluidPackage: IFluidRepoPackage) => {
additionalPackages = [
...additionalPackages,
...Packages.loadDir(path.join(resolvedRoot, fluidPackage.directory), undefined, fluidPackage.ignoredDirs)
]
});

if (services) {
assert(packageManifest.repoPackages.server.optional, "Requested optional server packages without passing parameters in package.json");
packageManifest.repoPackages.server.optional!.forEach((fluidPackage: IFluidRepoPackage) => {
additionalPackages = [
...additionalPackages,
...Packages.loadDir(path.join(resolvedRoot, fluidPackage.directory), undefined, fluidPackage.ignoredDirs)
]
});
} else {
packageManifest.repoPackages.server.required.forEach((fluidPackage: IFluidRepoPackage) => {
additionalPackages = [
...additionalPackages,
...Packages.loadDir(path.join(resolvedRoot, fluidPackage.directory), undefined, fluidPackage.ignoredDirs)
]
});
}

this.packages = new Packages(
[
...this.clientMonoRepo.packages,
...(this.serverMonoRepo?.packages || []),
...additionalPackages,
]
);
}

public createPackageMap() {
return new Map<string, Package>(this.packages.packages.map(pkg => [pkg.name, pkg]));
}

public reload() {
this.packages.packages.forEach(pkg => pkg.reload());
}

public static async ensureInstalled(packages: Package[], check: boolean = true) {
const installedMonoRepo = new Set<MonoRepo>();
const installPromises: Promise<any>[] = [];
for (const pkg of packages) {
if (!check || !await pkg.checkInstall(false)) {
if (pkg.monoRepo) {
if (!installedMonoRepo.has(pkg.monoRepo)) {
installedMonoRepo.add(pkg.monoRepo);
installPromises.push(pkg.monoRepo.install());
}
} else {
installPromises.push(pkg.install());
}
}
}
const rets = await Promise.all(installPromises);
return !rets.some(ret => ret.error);
}

public async install(nohoist: boolean = false) {
if (nohoist) {
return this.packages.noHoistInstall(this.resolvedRoot);
}
return FluidRepo.ensureInstalled(this.packages.packages);
}
};
65 changes: 0 additions & 65 deletions tools/build-tools/src/common/fluidRepoBase.ts

This file was deleted.

Loading