Add beachball change transformer (#9488)
* Add beachball change transformer Beachball has a relatively recent option, which allows modifying changefiles before trying to bump/publish. We can use this to workaround two common painpoints. 1. Changes backported to 0.69 and later will not need any modification to changefiles when cherry-picking. 2. We do some formatting to create consistency of omiting the version in change messages in our changelogs * Remove stale file * Change files * Fix bug around missing packages * Fuller JS env in setup * Simplify logic * Fix template path * use remote midgard-yarn on ubuntu agent * yaml * Build more * Move beachball config to its own package * Consistency * Cleanup yarn install logic for hosted vs managed images * Fixup lockfile issues * Update min to node 14 * Import shared variables and rename * Variable fixup
This commit is contained in:
Родитель
e8f0f0d844
Коммит
dfc6ca9c55
|
@ -2,30 +2,16 @@
|
|||
jobs:
|
||||
- job: MacTests
|
||||
displayName: macOS Tests
|
||||
|
||||
variables:
|
||||
- template: ../variables/macos.yml
|
||||
|
||||
pool:
|
||||
vmImage: $(VmImage)
|
||||
|
||||
timeoutInMinutes: 20 # how long to run the job before automatically cancelling
|
||||
cancelTimeoutInMinutes: 5 # how much time to give 'run always even if cancelled tasks' before killing them
|
||||
timeoutInMinutes: 20
|
||||
variables: [template: ../variables/shared.yml]
|
||||
pool: {vmImage: macOS-10.15}
|
||||
|
||||
steps:
|
||||
- template: ../templates/checkout-shallow.yml
|
||||
|
||||
# Explicitly set Node version and install midgard-yarn since we are
|
||||
# running on a public pool
|
||||
- task: NodeTool@0
|
||||
displayName: Set Node Version
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
|
||||
- script: npm install -g midgard-yarn@1.23.33
|
||||
displayName: Install midgard-yarn
|
||||
|
||||
- template: ../templates/prepare-js-env.yml
|
||||
parameters:
|
||||
agentImage: HostedImage
|
||||
|
||||
- script: yarn test
|
||||
displayName: yarn test
|
||||
|
|
|
@ -7,9 +7,11 @@ parameters:
|
|||
|
||||
jobs:
|
||||
- job: Setup
|
||||
timeoutInMinutes: 3
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
displayName: Setup
|
||||
timeoutInMinutes: 3 # Kill the job early to catch Beachball hangs
|
||||
variables: [template: ../variables/shared.yml]
|
||||
pool: {vmImage: ubuntu-latest}
|
||||
|
||||
steps:
|
||||
- template: ../templates/checkout-full.yml
|
||||
|
||||
|
@ -18,8 +20,12 @@ jobs:
|
|||
|
||||
- template: ../templates/compute-beachball-branch-name.yml
|
||||
|
||||
- script: npm install -g beachball@2.18.0
|
||||
displayName: Install beachball
|
||||
- template: ../templates/yarn-install.yml
|
||||
parameters:
|
||||
agentImage: HostedImage
|
||||
|
||||
- script: npx lage build --scope @rnw-scripts/beachball-config --no-deps
|
||||
displayName: Minimal build
|
||||
|
||||
- ${{ if eq(parameters.buildEnvironment, 'PullRequest') }}:
|
||||
- script: npx beachball check --branch origin/$(BeachBallBranchName) --verbose --changehint "##vso[task.logissue type=error]Run `yarn change` from root of repo to generate a change file."
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
# Steps to setup an environment that can run JavaScript executables
|
||||
parameters:
|
||||
- name: agentImage
|
||||
type: string
|
||||
default: ManagedImage
|
||||
values:
|
||||
- ManagedImage
|
||||
- HostedImage
|
||||
|
||||
steps:
|
||||
- ${{ if eq(parameters.agentImage, 'HostedImage') }}:
|
||||
- task: NodeTool@0
|
||||
displayName: Set Node Version
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
|
||||
- template: yarn-install.yml
|
||||
parameters:
|
||||
agentImage: ${{ parameters.agentImage }}
|
||||
|
||||
- script: yarn build
|
||||
displayName: yarn build
|
||||
|
|
|
@ -2,15 +2,22 @@ parameters:
|
|||
- name: workingDirectory
|
||||
type: string
|
||||
default: .
|
||||
- name: frozenLockfile
|
||||
type: boolean
|
||||
default: true
|
||||
- name: agentImage
|
||||
type: string
|
||||
default: ManagedImage
|
||||
values:
|
||||
- ManagedImage
|
||||
- HostedImage
|
||||
|
||||
steps:
|
||||
- ${{ if eq(parameters.frozenLockfile, true) }}:
|
||||
# When using our own images, prefer the machine-installed version of
|
||||
# `midgard-yarn`.
|
||||
- ${{ if eq(parameters.agentImage, 'ManagedImage') }}:
|
||||
- script: midgard-yarn --frozen-lockfile --cwd ${{ parameters.workingDirectory }}
|
||||
displayName: midgard-yarn (faster yarn install)
|
||||
|
||||
- ${{ if eq(parameters.frozenLockfile, false) }}:
|
||||
- script: midgard-yarn --cwd ${{ parameters.workingDirectory }}
|
||||
# If using an image we don't control, acquire a fixed version of midgard-yarn
|
||||
# before install
|
||||
- ${{ else }}:
|
||||
- script: npx --yes midgard-yarn@1.23.34 --frozen-lockfile --cwd ${{ parameters.workingDirectory }}
|
||||
displayName: midgard-yarn (faster yarn install)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
variables:
|
||||
- template: shared.yml
|
||||
|
||||
- name: VmImage
|
||||
value: macOS-10.15
|
|
@ -174,5 +174,6 @@ nul
|
|||
.verdaccio-db.json
|
||||
|
||||
# Graveyard of old packages (whose build-outputs may exist on disk after pull)
|
||||
/packages/@rnw-bots/*
|
||||
/packages/jest-environment-winappdriver/*
|
||||
/packages/node-rnw-rpc/*
|
||||
|
|
|
@ -4,5 +4,7 @@
|
|||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"orta.vscode-jest",
|
||||
"ms-azure-devops.azure-pipelines",
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
"files.exclude": {
|
||||
"**/.git": true
|
||||
},
|
||||
"files.associations": {
|
||||
"**/.ado/**/*.yml": "azure-pipelines"
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/lib": true,
|
||||
"**/dist": true
|
||||
"**/lib/**/*.js": true,
|
||||
"**/dist/**/*.js": true
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.format.enable": true,
|
||||
|
|
|
@ -1,26 +1 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
* @format
|
||||
* @ts-check
|
||||
*/
|
||||
|
||||
const {execSync} = require('child_process');
|
||||
|
||||
module.exports = {
|
||||
...require(`${__dirname}/packages/@rnw-scripts/generated-beachball-config/beachball.config.g.json`),
|
||||
|
||||
// Do not generate tags for monorepo packages by default, to avoid a GitHub
|
||||
// release for every package.
|
||||
gitTags: false,
|
||||
|
||||
hooks: {
|
||||
// Stamp versions when we publish a new package
|
||||
postbump: (_packagePath, name, version) => {
|
||||
if (name === 'react-native-windows') {
|
||||
console.log(`Stamping RNW Version ${version}`);
|
||||
execSync(`yarn stamp-version ${version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = require("@rnw-scripts/beachball-config");
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Sync variants",
|
||||
"packageName": "@react-native-windows/find-repo-root",
|
||||
"email": "ngerlem@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Sync variants",
|
||||
"packageName": "@react-native-windows/package-utils",
|
||||
"email": "ngerlem@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Use PackageReference for C++ dependencies",
|
||||
"packageName": "node-rnw-rpc",
|
||||
"email": "julio.rocha@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
"directory": "packages/@react-native-windows/find-repo-root"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-windows/fs": "^1.0.1",
|
||||
"find-up": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
*/
|
||||
|
||||
import findUp from 'find-up';
|
||||
import fs from '@react-native-windows/fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Find the root directory of a repo upward from cwd
|
||||
*/
|
||||
export default async (): Promise<string> => {
|
||||
async function findRepoRoot(): Promise<string> {
|
||||
const root = await findUp(
|
||||
async (dir: string): Promise<findUp.Match> => {
|
||||
return (await findUp.exists(path.join(dir, '.git'))) ? dir : undefined;
|
||||
|
@ -27,4 +28,27 @@ export default async (): Promise<string> => {
|
|||
}
|
||||
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously finds the root directory of a repo upward from cwd
|
||||
*/
|
||||
function findRepoRootSync(): string {
|
||||
const root = findUp.sync(
|
||||
(dir: string): findUp.Match => {
|
||||
return fs.existsSync(path.join(dir, '.git')) ? dir : undefined;
|
||||
},
|
||||
{type: 'directory'},
|
||||
);
|
||||
|
||||
if (!root) {
|
||||
throw new Error(
|
||||
'Unable to find the root of react-native-windows. Are you running within the repo?',
|
||||
);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
const exportObj = Object.assign(findRepoRoot, {sync: findRepoRootSync});
|
||||
export default exportObj;
|
||||
|
|
|
@ -120,6 +120,23 @@ export async function enumerateRepoPackages(
|
|||
return filteredPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously Finds monorepo-local packages matching a given predicate. The
|
||||
* root package is not included.
|
||||
*
|
||||
* @param pred predicate describing whether to match a package
|
||||
*/
|
||||
export function enumerateRepoPackagesSync(
|
||||
pred: (pkg: NpmPackage) => boolean = () => true,
|
||||
): WritableNpmPackage[] {
|
||||
const repoRoot = findRepoRoot.sync();
|
||||
const allPackges = getMonorepoPackages(repoRoot).map(
|
||||
(pkg) => new WritableNpmPackage(pkg.location, pkg.package),
|
||||
);
|
||||
|
||||
return allPackges.filter(pred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a package with a given name (local or dependency)
|
||||
*/
|
||||
|
@ -164,3 +181,16 @@ export async function findRepoPackage(
|
|||
return packages[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously a monorepo-local package with a given name
|
||||
*/
|
||||
export function findRepoPackageSync(name: string): WritableNpmPackage | null {
|
||||
const packages = enumerateRepoPackagesSync((p) => p.json.name === name);
|
||||
|
||||
if (packages.length === 0) {
|
||||
return null;
|
||||
} else {
|
||||
return packages[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
import { Context } from "@azure/functions";
|
||||
declare const _default: (context: Context) => Promise<void>;
|
||||
export default _default;
|
|
@ -1,6 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.default = async (context) => {
|
||||
context.log('Hello world');
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../HeartbeatFunction/index.ts"],"names":[],"mappings":";;AAEA,kBAAe,KAAK,EAAE,OAAgB,EAAE,EAAE;IACtC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAC/B,CAAC,CAAC","sourcesContent":["import { Context } from \"@azure/functions\"\n\nexport default async (context: Context) => {\n context.log('Hello world');\n};\n"]}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"name": "@rnw-bots/coordinator",
|
||||
"version": "1.0.12",
|
||||
"license": "MIT",
|
||||
"description": "Azure functions application for coordinating react-native-windows bots",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/react-native-windows.git",
|
||||
"directory": "packages/@rnw-bots/coordinator"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rnw-scripts build",
|
||||
"clean": "rnw-scripts clean",
|
||||
"lint": "rnw-scripts lint",
|
||||
"lint:fix": "rnw-scripts lint:fix",
|
||||
"start": "func start --typescript",
|
||||
"test": "rnw-scripts test",
|
||||
"watch": "rnw-scripts watch"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@azure/functions": "^1.0.2-beta2",
|
||||
"@rnw-scripts/eslint-config": "1.1.9",
|
||||
"@rnw-scripts/jest-unittest-config": "1.2.4",
|
||||
"@rnw-scripts/just-task": "2.2.1",
|
||||
"@rnw-scripts/ts-config": "2.0.1",
|
||||
"@types/node": "^14.14.22",
|
||||
"babel-jest": "^26.3.0",
|
||||
"eslint": "^7.32.0",
|
||||
"jest": "^26.6.3",
|
||||
"just-scripts": "^1.3.3",
|
||||
"prettier": "^2.4.1",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
lib/
|
||||
lib-commonjs/
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "@rnw-scripts/beachball-config",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rnw-scripts build",
|
||||
"clean": "rnw-scripts clean",
|
||||
"lint": "rnw-scripts lint",
|
||||
"lint:fix": "rnw-scripts lint:fix",
|
||||
"watch": "rnw-scripts watch"
|
||||
},
|
||||
"main": "lib-commonjs/beachball.config.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/react-native-windows.git",
|
||||
"directory": "packages/@rnw-scripts/beachball-config"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-windows/package-utils": "0.0.0-canary.25",
|
||||
"@rnw-scripts/stamp-version": "0.0.0",
|
||||
"find-up": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rnw-scripts/eslint-config": "1.1.11",
|
||||
"@rnw-scripts/just-task": "2.2.3",
|
||||
"@rnw-scripts/ts-config": "2.0.2",
|
||||
"@types/node": "^14.14.22",
|
||||
"beachball": "^2.20.0",
|
||||
"eslint": "^7.32.0",
|
||||
"just-scripts": "^1.3.3",
|
||||
"prettier": "^2.4.1",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"files": [
|
||||
"lib-commonjs"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 14.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {execSync} from 'child_process';
|
||||
import {findRepoPackageSync} from '@react-native-windows/package-utils';
|
||||
|
||||
import type {BeachballOptions} from 'beachball/lib/types/BeachballOptions';
|
||||
import type {ChangeInfo} from 'beachball/lib/types/ChangeInfo';
|
||||
|
||||
const Options: BeachballOptions = {
|
||||
...require("@rnw-scripts/generated-beachball-config"),
|
||||
|
||||
// Do not generate tags for monorepo packages by default, to avoid a GitHub
|
||||
// release for every package.
|
||||
gitTags: false,
|
||||
|
||||
hooks: {
|
||||
// Stamp versions when we publish a new package
|
||||
postbump: (_packagePath, name, version) => {
|
||||
if (name === 'react-native-windows') {
|
||||
console.log(`Stamping RNW Version ${version}`);
|
||||
execSync(`yarn stamp-version ${version}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
transform: {
|
||||
changeFiles: (changeInfo) => Array.isArray(changeInfo.changes)
|
||||
? {...changeInfo, changes: changeInfo.changes.map(transformChangeInfo)}
|
||||
: transformChangeInfo(changeInfo as ChangeInfo),
|
||||
}
|
||||
}
|
||||
|
||||
function transformChangeInfo(changeInfo: ChangeInfo) : ChangeInfo {
|
||||
return {
|
||||
...changeInfo,
|
||||
type: correctChangeType(changeInfo),
|
||||
comment: formatComment(changeInfo.comment),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function correctChangeType(changeInfo: ChangeInfo) {
|
||||
// Changes made to our main branch are often rolled into prerelease packages,
|
||||
// where a released branch should treat these changes as creating a new patch
|
||||
// release.
|
||||
if (changeInfo.type === 'prerelease' && !isPrerelease(changeInfo.packageName)) {
|
||||
return 'patch';
|
||||
}
|
||||
|
||||
return changeInfo.type;
|
||||
}
|
||||
|
||||
function isPrerelease(packageName: string): boolean {
|
||||
const packageJson = findRepoPackageSync(packageName)?.json;
|
||||
return packageJson && packageJson.version.includes('-');
|
||||
}
|
||||
|
||||
function formatComment(comment: string): string {
|
||||
// Remove versions from messages that look like "[0.xx] Message"
|
||||
return comment.match(/(\s*\[[\d\.]+\]\s*)?((.|\n)*)/)?.[2] ?? comment;
|
||||
}
|
||||
|
||||
module.exports = Options;
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "@rnw-scripts/ts-config",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Загрузка…
Ссылка в новой задаче