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

feat(generate:typetests)!: Make type tests configurable per-branch #12849

Merged
merged 30 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f9f1d87
feat(generate:typetests): Make type tests configurable per-branch
tylerbutler Nov 8, 2022
33dbc02
updates
tylerbutler Nov 10, 2022
27f79ac
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 10, 2022
15d724c
formatting
tylerbutler Nov 10, 2022
67db2ee
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 11, 2022
f4d713f
updates
tylerbutler Nov 11, 2022
f600918
updates
tylerbutler Nov 11, 2022
55246d0
policy
tylerbutler Nov 11, 2022
7ed8899
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 11, 2022
63fb832
updates
tylerbutler Nov 11, 2022
fdca17a
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 11, 2022
e38061a
updates
tylerbutler Nov 11, 2022
56b33ed
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 11, 2022
2c0b042
Update build-tools/packages/build-cli/docs/typetestDetails.md
tylerbutler Nov 11, 2022
3561aaa
Update build-tools/packages/build-cli/docs/typetestDetails.md
tylerbutler Nov 11, 2022
bb70fb0
Update build-tools/packages/build-cli/.eslintrc.cjs
tylerbutler Nov 11, 2022
5f6756b
Apply suggestions from code review
tylerbutler Nov 15, 2022
eb72d80
feedback
tylerbutler Nov 15, 2022
8041644
full build
tylerbutler Nov 15, 2022
361c9e5
cleanup
tylerbutler Nov 15, 2022
7025b2b
feedback
tylerbutler Nov 16, 2022
4eda596
docs
tylerbutler Nov 16, 2022
4a758e5
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 16, 2022
3dbdff3
policy
tylerbutler Nov 16, 2022
85df5c8
fixup
tylerbutler Nov 16, 2022
71ea4ae
add docs on pinning
tylerbutler Nov 16, 2022
b597817
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 16, 2022
29cd509
Update build-tools/packages/build-cli/src/lib/package.ts
tylerbutler Nov 16, 2022
8fba738
Merge branch 'main' into cli/typetest-branch-config
tylerbutler Nov 16, 2022
5660bd2
cleanup
tylerbutler Nov 16, 2022
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
3 changes: 3 additions & 0 deletions build-tools/packages/build-cli/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ module.exports = {
{
allow: [
"@oclif/core/lib/interfaces",
"@oclif/core/lib/util",
"oclif/lib/commands/**",
"oclif/lib/util",
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
"npm-check-updates/build/src/types/**",
"**/commands/**",
],
Expand Down
2 changes: 1 addition & 1 deletion build-tools/packages/build-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ $ npm install -g @fluid-tools/build-cli
$ flub COMMAND
running command...
$ flub (--version|-V)
@fluid-tools/build-cli/0.5.0
@fluid-tools/build-cli/0.6.0
$ flub --help [COMMAND]
USAGE
$ flub COMMAND
Expand Down
16 changes: 9 additions & 7 deletions build-tools/packages/build-cli/docs/generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,17 @@ Generates type tests based on the individual package settings in package.json.
```
USAGE
$ flub generate typetests [-d <value> | --packages | -g client|server|azure|build-tools] [--prepare | --generate]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify --packages: "Run on all independent packages in the repo." ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a shortcut to run generation on all independent packages, like build-common, common-utils, etc. The alternative is to use the --dir option and pass the path to the package, but this is more convenient when you're updating them all. Clarified in the flag docs.

(--exact <value> | | -s
^previousMajor|^previousMinor|~previousMajor|~previousMinor|previousMajor|previousMinor|baseMinor|baseMajor)
[--reset | ] [--generateInName] [-v]
[--exact <value> | | -s ^previousMajor|^previousMinor|~previousMajor|~previousMinor|previousMajor|previousMinor|pre
viousPatch|baseMinor|baseMajor|~baseMinor] [--reset | ] [--generateInName] [-v]

FLAGS
-d, --dir=<value> Run on the package in this directory.
-g, --releaseGroup=<option> Run on all packages within this release group.
<options: client|server|azure|build-tools>
-s, --versionConstraint=<option> (required) The type of version constraint to use for previous versions. Only applies
to the prepare phase.
-s, --versionConstraint=<option> The type of version constraint to use for previous versions. Only applies to the
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
prepare phase.
<options: ^previousMajor|^previousMinor|~previousMajor|~previousMinor|previousMajor|
previousMinor|baseMinor|baseMajor>
previousMinor|previousPatch|baseMinor|baseMajor|~baseMinor>
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
-v, --verbose Verbose logging.
--exact=<value> An exact string to use as the previous version constraint. The string will be used
as-is. Only applies to the prepare phase.
Expand All @@ -151,7 +150,10 @@ DESCRIPTION
preparation. This is useful when resetting the type tests to a clean state, such as after a major release.

Generating test modules takes the type test information from package.json, most notably any known broken type tests,
and generates an appropriate
and generates test files that should be committed.

To learn more about how to configure type tests, see the detailed documentation at
<https://github.com/microsoft/FluidFramework/blob/main/build-tools/packages/build-cli/docs/typetestDetails.md>.

EXAMPLES
Prepare the package.json for all packages in the client release group.
Expand Down
154 changes: 154 additions & 0 deletions build-tools/packages/build-cli/docs/typetestDetails.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Further information about `generate typetests`

The `generate typetests` command generates type compatibility tests based on the individual package settings in
package.json.

## What are type compatibility tests?

Type compatibility tests are automatically generated test cases that check for type incompatibilities across package
versions. They work by comparing types in the current version to the types in a previous version. The generated tests
use the previous type in place of the new type, and vice-versa.

See the [API Type Validation][] page in the Fluid Framework wiki for more information about type compatibility tests,
including how to annotate expected type incompatibilities to fix failing tests.

## Configuring type tests

Type test generation is primarily configured in the package.json file of the package being tested, in the
`typeValidation` section:

```json
"typeValidation": {
"disabled": false,
"version": "1.1.0",
"broken": {
"InterfaceDeclaration_AzureClientProps": {
"forwardCompat": false
}
}
}
```

The `broken` section is used to indicate known breaking changes. Type tests can be completely disabled for a package
using the `disabled1 property. See [API Type Validation][] for more information.
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved

Generating type tests has two parts: _preparing package.json_ and _generating test modules_. By default, both steps are
run for each package. You can run only one part at a time using the `--prepare` and `--generate` flags.

[api type validation]: https://github.com/microsoft/FluidFramework/wiki/API-Type-Validation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious on your thoughts WRT conventions for where to put link aliases. I find it useful to be able to look in a single place in a given document for the links so I know what things I can re-use and what I need to define as I go.

Would it make sense to move this to the bottom under a "links" comment like we generate for content on the website?

Feel free to disregard in the context of the PR - it just took me a few seconds to find where this was defined as I was reviewing, since I wanted to make sure it was defined somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually put them at the end of the section in which they're used unless they're used in several places. Reason being that sections get moved/reorganized, and links sometimes break when they're far away from the content. But I don't care too much.


## Preparing package.json

_Preparing package.json_ determines the baseline previous version to use, then sets that version in package.json. If the
previous version changes after running preparation, then `npm install` must be run before the generate step will run
correctly.

Optionally, any type tests that are marked "broken" in package.json can be reset using the `--reset` flag during
preparation. This is useful when resetting the type tests to a clean state, such as after a major release.

## Generating tests

Generating test modules takes the type test information from package.json, most notably any known broken type tests, and
generates test files that should be committed. By default, the generated files will contain `.generated` in their name,
but this can be suppressed with the `--no-generateInName` flag.

For more detailed usage information see the
[bump deps command reference](bump.md#flub-bump-deps-packageorreleasegroup).

tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
## Branch configuration

Type tests can be configured to use different baseline versions on a given branch depending on the type of release that
the branch is designated for. For example, for the client release group, the _next_ branch is the _major version series
branch_ and _main_ is the _minor version series branch_. This can be declared in the root package.json, in the
`fluidBuild.repoPackages` section. For example, the following configuration designates the _main_ and _lts_ branches as
minor version series branches, while the _next_ branch is designated for major releases.

```json
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
"fluidBuild": {
"repoPackages": {
"client": {
"directory": "",
"ignoredDirs": [],
"branchReleaseTypes": {
"main": "minor",
"lts": "minor",
"release/**": "patch",
"next": "major"
}
}
}
}
```

The branch names can be globs. They are matched using [minimatch](https://www.npmjs.com/package/minimatch).

The type test generator takes this information into account when calculating the baseline version to use when it's run
on a particular branch. Baseline versions are set as follows based on the branch release designation:

| Branch release designation | Baseline version | Example: version 2.3.4 |
| -------------------------- | ---------------- | ---------------------- |
| `patch` | `previousPatch` | **2.3.3** |
| `minor` | `^previousMinor` | **^2.2.0** |
| `major` | `^previousMajor` | **^1.0.0** |

### Configuring a branch for a specific baseline

It may be useful to configure a branch for a specific baseline instead of the default based on the branch release
designation. To do this, you can use any of the following strings instead of major/minor/patch.

- `baseMajor`
Copy link

@ssimic2 ssimic2 Nov 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe some super-short description here on "base" would be helpful. When I think of "previous" I think about previous to existing branch version, but "base" I cannot fit into my mental model, or at least I assume we don't want to run compat tests against self :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified both here and in the tsdocs:

The "base" versions are calculated by zeroing out all version segments lower than the base. That is, for a version v,
the baseMajor version is ${v.major}.0.0 and the baseMinor version is ${v.major}.${v.minor}.0.

The "previous" versions work similarly, but the major/minor/patch segment is reduced by 1. That is, for a version v,
the previousMajor version is ${min(v.major - 1, 1)}.0.0, the previousMinor version is
${v.major}.${min(v.minor - 1, 0)}.0, and the previousPatch is ${v.major}.${v.minor}.${min(v.patch - 1, 0)}.0.

The "previous" versions never roll back below 1 for the major version and 0 for minor and patch. That is, the
previousMajor, previousMinor, and previousPatch versions for 1.0.0 are all 1.0.0.

- `baseMinor`
- `~baseMinor`
- `previousPatch`
- `previousMinor`
- `previousMajor`
- `^previousMajor`
- `^previousMinor`
- `~previousMajor`
- `~previousMinor`

Given the version 3.4.5:
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved

| Previous version style | Baseline version for **3.4.5** |
| ---------------------- | ------------------------------ |
| `baseMajor` | 3.0.0 |
| `baseMinor` | 3.4.0 |
| `~baseMinor` | ~3.4.0 |
| `previousPatch` | 3.4.4 |
| `previousMajor` | 2.0.0 |
| `previousMinor` | 3.3.0 |
| `^previousMajor` | ^2.0.0 |
| `^previousMinor` | ^3.3.0 |
| `~previousMajor` | ~2.0.0 |
| `~previousMinor` | ~3.3.0 |


Given the version 2.0.0-internal.2.3.5:

| Previous version style | Baseline version for **2.0.0-internal.2.3.5** |
| ---------------------- | --------------------------------------------- |
| `baseMajor` | 2.0.0-internal.2.0.0 |
| `baseMinor` | 2.0.0-internal.2.3.0 |
| `~baseMinor` | >=2.0.0-internal.2.3.0 <2.0.0-internal.3.0.0 |
| `previousPatch` | 2.0.0-internal.2.3.4 |
| `previousMajor` | 2.0.0-internal.1.0.0 |
| `previousMinor` | 2.0.0-internal.2.2.0 |
| `^previousMajor` | >=2.0.0-internal.1.0.0 <2.0.0-internal.2.0.0 |
| `^previousMinor` | >=2.0.0-internal.2.2.0 <2.0.0-internal.3.0.0 |
| `~previousMajor` | >=2.0.0-internal.1.0.0 <2.0.0-internal.1.1.0 |
| `~previousMinor` | >=2.0.0-internal.2.2.0 <2.0.0-internal.2.2.0 |

Given the version 2.0.0-internal.2.0.0:

| Previous version style | Baseline version for **2.0.0-internal.2.0.0** |
| ---------------------- | --------------------------------------------- |
| `baseMajor` | 2.0.0-internal.2.0.0 |
| `baseMinor` | 2.0.0-internal.2.0.0 |
| `~baseMinor` | >=2.0.0-internal.2.0.0 <2.0.0-internal.2.1.0 |
| `previousPatch` | 2.0.0-internal.2.0.0 |
| `previousMajor` | 2.0.0-internal.1.0.0 |
| `previousMinor` | 2.0.0-internal.2.0.0 |
| `^previousMajor` | >=2.0.0-internal.1.0.0 <2.0.0-internal.2.0.0 |
| `^previousMinor` | >=2.0.0-internal.2.0.0 <2.0.0-internal.3.0.0 |
| `~previousMajor` | >=2.0.0-internal.1.0.0 <2.0.0-internal.1.1.0 |
| `~previousMinor` | >=2.0.0-internal.2.0.0 <2.0.0-internal.2.1.0 |
24 changes: 17 additions & 7 deletions build-tools/packages/build-cli/src/commands/generate/typetests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,29 @@
import { CliUx, Flags } from "@oclif/core";
import chalk from "chalk";

import { generateTests, getAndUpdatePackageDetails } from "@fluidframework/build-tools";
import {
PreviousVersionStyle,
generateTests,
getAndUpdatePackageDetails,
} from "@fluidframework/build-tools";

import { BaseCommand } from "../../base";
import { releaseGroupFlag } from "../../flags";

export default class GenerateTypeTestsCommand extends BaseCommand<
typeof GenerateTypeTestsCommand.flags
> {
static summary =
"Generates type tests based on the individual package settings in package.json.";
static description = `Generates type tests based on the individual package settings in package.json.

static description = `Generating type tests has two parts: preparing package.json and generating test modules. By default, both steps are run for each package. You can run only one part at a time using the --prepare and --generate flags.
Generating type tests has two parts: preparing package.json and generating test modules. By default, both steps are run for each package. You can run only one part at a time using the --prepare and --generate flags.

Preparing package.json determines the baseline previous version to use, then sets that version in package.json. If the previous version changes after running preparation, then npm install must be run before the generate step will run correctly.

Optionally, any type tests that are marked "broken" in package.json can be reset using the --reset flag during preparation. This is useful when resetting the type tests to a clean state, such as after a major release.

Generating test modules takes the type test information from package.json, most notably any known broken type tests, and generates an appropriate `;
Generating test modules takes the type test information from package.json, most notably any known broken type tests, and generates test files that should be committed.

To learn more about how to configure type tests, see the detailed documentation at <https://github.com/microsoft/FluidFramework/blob/main/build-tools/packages/build-cli/docs/typetestDetails.md>.`;

static flags = {
dir: Flags.directory({
Expand Down Expand Up @@ -59,10 +64,11 @@ export default class GenerateTypeTestsCommand extends BaseCommand<
"~previousMinor",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we generate this list from the PreviousVersionStyle type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a union type, so no, not as far as I know.

"previousMajor",
"previousMinor",
"previousPatch",
"baseMinor",
"baseMajor",
"~baseMinor",
],
required: true,
}),
exact: Flags.string({
description:
Expand Down Expand Up @@ -140,6 +146,7 @@ export default class GenerateTypeTestsCommand extends BaseCommand<
this.info(`Finding package in directory: ${dir}`);
packageDirs.push(dir);
} else {
// eslint-disable-next-line @typescript-eslint/no-shadow
const context = await this.getContext();
if (independentPackages) {
this.info(`Finding independent packages`);
Expand All @@ -160,8 +167,10 @@ export default class GenerateTypeTestsCommand extends BaseCommand<
});
}

const context = await this.getContext();
const concurrency = 25;
const runningGenerates: Promise<boolean>[] = [];

// this loop incrementally builds up the runningGenerates promise list
// each dir with an index greater than concurrency looks back the concurrency value
// to determine when to run
Expand All @@ -184,9 +193,10 @@ export default class GenerateTypeTestsCommand extends BaseCommand<
try {
const start = Date.now();
const packageData = await getAndUpdatePackageDetails(
context,
packageDir,
/* writeUpdates */ runPrepare,
flags.versionConstraint as any,
flags.versionConstraint as PreviousVersionStyle | undefined,
flags.exact,
flags.reset,
).finally(() => output.push(`Loaded(${Date.now() - start}ms)`));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class Context {
public readonly fullPackageMap: Map<string, Package>;

private readonly timer: Timer;
private readonly packageManifest: IPackageManifest;
public readonly packageManifest: IPackageManifest;
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
private readonly newBranches: string[] = [];
private readonly newTags: string[] = [];

Expand Down
6 changes: 6 additions & 0 deletions build-tools/packages/build-tools/src/common/fluidRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*/
import * as path from "path";

import { VersionBumpType } from "@fluid-tools/version-tools";

import { PreviousVersionStyle } from "../typeValidator/packageJson";
import { getPackageManifest } from "./fluidUtils";
import { Logger, defaultLogger } from "./logging";
import { MonoRepo, MonoRepoKind, isMonoRepoKind } from "./monoRepo";
Expand Down Expand Up @@ -33,6 +36,9 @@ export interface PolicyConfig {
export interface IFluidRepoPackage {
directory: string;
ignoredDirs?: string[];
branchReleaseTypes?: {
tylerbutler marked this conversation as resolved.
Show resolved Hide resolved
[name: string]: VersionBumpType | PreviousVersionStyle;
};
}

export type IFluidRepoPackageEntry = string | IFluidRepoPackage | (string | IFluidRepoPackage)[];
Expand Down
1 change: 1 addition & 0 deletions build-tools/packages/build-tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ export { policyHandlers } from "./repoPolicyCheck/handlers";
export { generateMonoRepoInstallPackageJson } from "./genMonoRepoPackageJson/lib";
export { findPackagesUnderPath, getAndUpdatePackageDetails } from "./typeValidator/packageJson";
export { generateTests } from "./typeValidator/testGeneration";
export { type PreviousVersionStyle } from "./typeValidator/packageJson";
Loading