diff --git a/.ng-dev/config.ts b/.ng-dev/config.ts index 573b9f1847..4f059b5a6e 100644 --- a/.ng-dev/config.ts +++ b/.ng-dev/config.ts @@ -3,6 +3,7 @@ import {commitMessage} from './commit-message'; import {format} from './format'; import {github} from './github'; import {merge} from './merge'; +import {release} from './release'; module.exports = { commitMessage, @@ -10,4 +11,5 @@ module.exports = { github, merge, caretaker, + release, }; diff --git a/.ng-dev/release.ts b/.ng-dev/release.ts new file mode 100644 index 0000000000..b285ece61a --- /dev/null +++ b/.ng-dev/release.ts @@ -0,0 +1,33 @@ +import {join} from 'path'; +import {exec} from 'shelljs'; +import {ReleaseConfig} from '../dev-infra/release/config'; + +/** Configuration for the `ng-dev release` command. */ +export const release: ReleaseConfig = { + npmPackages: [ + '@angular/animations', + '@angular/bazel', + '@angular/common', + '@angular/compiler', + '@angular/compiler-cli', + '@angular/core', + '@angular/elements', + '@angular/forms', + '@angular/language-service', + '@angular/localize', + '@angular/platform-browser', + '@angular/platform-browser-dynamic', + '@angular/platform-server', + '@angular/platform-webworker', + '@angular/platform-webworker-dynamic', + '@angular/router', + '@angular/service-worker', + '@angular/upgrade', + ], + // TODO: Implement release package building here. + buildPackages: async () => [], + // TODO: This can be removed once there is a org-wide tool for changelog generation. + generateReleaseNotesForHead: async () => { + exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')}); + }, +}; diff --git a/dev-infra/release/config/BUILD.bazel b/dev-infra/release/config/BUILD.bazel new file mode 100644 index 0000000000..b8f17b6bf2 --- /dev/null +++ b/dev-infra/release/config/BUILD.bazel @@ -0,0 +1,14 @@ +load("@npm_bazel_typescript//:index.bzl", "ts_library") + +ts_library( + name = "config", + srcs = glob([ + "**/*.ts", + ]), + module_name = "@angular/dev-infra-private/release/config", + visibility = ["//dev-infra:__subpackages__"], + deps = [ + "//dev-infra/utils", + "@npm//@types/semver", + ], +) diff --git a/dev-infra/release/config/index.ts b/dev-infra/release/config/index.ts new file mode 100644 index 0000000000..da1f759116 --- /dev/null +++ b/dev-infra/release/config/index.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as semver from 'semver'; + +import {assertNoErrors, getConfig, NgDevConfig} from '../../utils/config'; + +/** Interface describing a built package. */ +export interface BuiltPackage { + /** Name of the package. */ + name: string; + /** Path to the package output directory. */ + outputPath: string; +} + +/** Configuration for staging and publishing a release. */ +export interface ReleaseConfig { + /** Registry URL used for publishing release packages. Defaults to the NPM registry. */ + publishRegistry?: string; + /** List of NPM packages that are published as part of this project. */ + npmPackages: string[]; + /** Builds release packages and returns a list of paths pointing to the output. */ + buildPackages: () => Promise; + /** Generates the release notes from the most recent tag to `HEAD`. */ + generateReleaseNotesForHead: (outputPath: string) => Promise; + /** + * Gets a pattern for extracting the release notes of the a given version. + * @returns A pattern matching the notes for a given version (including the header). + */ + // TODO: Remove this in favor of a canonical changelog format across the Angular organization. + extractReleaseNotesPattern?: (version: semver.SemVer) => RegExp; +} + +/** Configuration for releases in the dev-infra configuration. */ +export type DevInfraReleaseConfig = NgDevConfig<{release: ReleaseConfig}>; + +/** Retrieve and validate the config as `ReleaseConfig`. */ +export function getReleaseConfig(config: Partial = getConfig()): + ReleaseConfig { + // List of errors encountered validating the config. + const errors: string[] = []; + + if (config.release === undefined) { + errors.push(`No configuration defined for "release"`); + } + if (config.release?.npmPackages === undefined) { + errors.push(`No "npmPackages" configured for releasing.`); + } + if (config.release?.buildPackages === undefined) { + errors.push(`No "buildPackages" function configured for releasing.`); + } + if (config.release?.generateReleaseNotesForHead === undefined) { + errors.push(`No "generateReleaseNotesForHead" function configured for releasing.`); + } + + assertNoErrors(errors); + return config.release!; +}