Skip to content

Commit

Permalink
backport release script improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Jan 15, 2025
1 parent 4262635 commit 46406b1
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 22 deletions.
12 changes: 10 additions & 2 deletions .github/workflows/release_publish-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name: 0. Release > Beta
on:
workflow_dispatch:
inputs:
train:
description: 'If not the current primary release train, the prior major version for which to perform a new release'
required: true
default: null
type: choice
options:
- null
- v4
# This input is used to determine whether to start/continue a beta-cycle vs mirror from canary.
#
# A beta-cycle "forks" from canary. It starts by updating the beta branch to the current state
Expand Down Expand Up @@ -74,14 +82,14 @@ jobs:
# For beta-cycle we always increment from the branch state
# For mirror we increment from the last beta version, unless it's start of a new cycle.
if: github.event.inputs.kind == 'beta-cycle' || github.event.inputs.is-cycle-start == 'true'
run: bun release exec publish beta
run: bun release exec publish beta --train=${{ github.event.inputs.train }}
env:
FORCE_COLOR: 2
CI: true
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
- name: Publish New Mirror Release
if: github.event.inputs.kind == 'mirror'
run: bun release exec publish beta --from=${{ steps.version.outputs.value }}
run: bun release exec publish beta --train=${{ github.event.inputs.train }} --from=${{ steps.version.outputs.value }}
env:
FORCE_COLOR: 2
CI: true
Expand Down
28 changes: 26 additions & 2 deletions .github/workflows/release_publish-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ name: 0. Release > Canary
on:
workflow_dispatch:
inputs:
train:
name: Train
description: 'If not the current primary release train, the prior major version for which to perform a new release'
required: false
default: ''
type: choice
options:
- ''
- v4
increment:
name: Increment
description: 'Type of Version Bump To Perform'
required: true
default: 'patch'
Expand All @@ -12,6 +22,12 @@ on:
- patch
- minor
- major
dryRun:
name: Dry Run
description: 'Whether to perform a dry run'
required: true
default: false
type: boolean
schedule:
- cron: '0 20 * * 2' # weekly (Tuesday) 12 PM PST
- cron: '0 20 * * 5' # weekly (Friday) 12 PM PST
Expand All @@ -34,13 +50,21 @@ jobs:
run: |
echo "Releases may only be performed from the main branch."
exit 1
- name: Desired Branch
id: desired-branch
run: |
if [[ github.event.inputs.train ]]; then
echo "DESIRED_BRANCH=${{github.event.inputs.train}}-main" >> "$GITHUB_OUTPUT"
else
echo "DESIRED_BRANCH=main" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
with:
fetch-depth: 1
fetch-tags: true
show-progress: false
token: ${{ secrets.GH_DEPLOY_TOKEN }}
ref: main
ref: ${{ steps.desired-branch.outputs.DESIRED_BRANCH }}
- name: Check should run if HEAD is untagged
run: |
echo "HEAD is $(git name-rev --tags --name-only $(git rev-parse HEAD))"
Expand All @@ -56,7 +80,7 @@ jobs:
git config --local user.email ${{ secrets.GH_DEPLOY_EMAIL }}
git config --local user.name ${{ secrets.GH_DEPLOY_NAME }}
- name: Publish with script
run: bun release exec canary --increment=${{ github.event.inputs.increment }}
run: bun release exec canary --train=${{ github.event.inputs.train }} --increment=${{ github.event.inputs.increment }} --dry-run=${{ github.event.inputs.dryRun }}
env:
FORCE_COLOR: 2
CI: true
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/release_publish-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name: 0. Release > Stable
on:
workflow_dispatch:
inputs:
train:
description: 'If not the current primary release train, the prior major version for which to perform a new release'
required: true
default: null
type: choice
options:
- null
- v4
source-branch:
description: 'If starting a new cycle, or reversioning, the source branch to update the release branch from'
required: false
Expand Down Expand Up @@ -84,7 +92,7 @@ jobs:
# Then we do the default patch increment from the current branch state.
# This handles both start-of-cycle and bugfix releases.
if: github.event.inputs.from-version == null
run: bun release publish release
run: bun release publish release --train=${{ github.event.inputs.train }}
env:
FORCE_COLOR: 2
CI: true
Expand Down
5 changes: 3 additions & 2 deletions release/core/publish/steps/generate-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import chalk from 'chalk';
import { CHANNEL, npmDistTagForChannelAndVersion } from '../../../utils/channel';
import { CHANNEL, npmDistTagForChannelAndVersion, VALID_TRAINS } from '../../../utils/channel';

import { APPLIED_STRATEGY, Package, STRATEGY } from '../../../utils/package';
import { getNextVersion } from '../../utils/next-version';
Expand Down Expand Up @@ -70,6 +70,7 @@ export async function applyStrategy(
toPackages: Map<string, Package> = baseVersionPackages
): Promise<AppliedStrategy> {
const channel = config.get('channel') as CHANNEL;
const train = config.get('train') as VALID_TRAINS | '';
const increment = config.get('increment') as 'major' | 'minor' | 'patch';
const applied_strategies = new Map<string, APPLIED_STRATEGY>();
const private_pkgs = new Map<string, APPLIED_STRATEGY>();
Expand Down Expand Up @@ -140,7 +141,7 @@ export async function applyStrategy(
// major and minor bumps may only occur on beta|canary|release|lts
// and never lts-* or release-* and so existing fromVersion is safe
// to use.
applied_strategy.distTag = npmDistTagForChannelAndVersion(channel, applied_strategy.fromVersion);
applied_strategy.distTag = npmDistTagForChannelAndVersion(channel, applied_strategy.fromVersion, train);
applied_strategies.set(name, applied_strategy);

applied_strategy.private ? private_pkgs.set(name, applied_strategy) : public_pks.set(name, applied_strategy);
Expand Down
40 changes: 34 additions & 6 deletions release/utils/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,30 @@ import semver from 'semver';

export type LTS_TAG = `lts-${number}-${number}`;
export type RELEASE_TAG = `release-${number}-${number}`;
export type NPM_DIST_TAG = 'latest' | 'beta' | 'canary' | 'lts' | LTS_TAG | RELEASE_TAG;
export type VALID_BRANCHES = 'main' | 'beta' | 'release' | LTS_TAG | RELEASE_TAG;
export type NPM_DIST_TAG =
| `${VALID_TRAINS}-canary`
| `${VALID_TRAINS}-beta`
| 'latest'
| 'beta'
| 'canary'
| 'lts'
| LTS_TAG
| RELEASE_TAG;
export type VALID_BRANCHES =
| `${VALID_TRAINS}-main`
| `${VALID_TRAINS}-beta`
| 'main'
| 'beta'
| 'release'
| LTS_TAG
| RELEASE_TAG;
export type CHANNEL = 'lts' | 'release' | 'beta' | 'canary' | 'lts-prev' | 'release-prev';
export type ALPHA_SEMVER = `${number}.${number}.${number}-alpha.${number}`;
export type BETA_SEMVER = `${number}.${number}.${number}-beta.${number}`;
export type RELEASE_SEMVER = `${number}.${number}.${number}`;
export type SEMVER_VERSION = RELEASE_SEMVER | BETA_SEMVER | ALPHA_SEMVER;
export type VALID_TRAINS = 'v4';

/**
* The strategy type is used to determine the next version of a package
* and how to handle types during publish.
Expand Down Expand Up @@ -61,7 +78,11 @@ export function channelForBranch(branch: string, currentVersion: SEMVER_VERSION,
throw new Error(`Attempting to release from an unexpected branch ${branch}`);
}

export function npmDistTagForChannelAndVersion(channel: CHANNEL, package_version: SEMVER_VERSION): NPM_DIST_TAG {
export function npmDistTagForChannelAndVersion(
channel: CHANNEL,
package_version: SEMVER_VERSION,
train: VALID_TRAINS | ''
): NPM_DIST_TAG {
const major = semver.major(package_version);
const minor = semver.minor(package_version);

Expand All @@ -74,8 +95,10 @@ export function npmDistTagForChannelAndVersion(channel: CHANNEL, package_version
}

switch (channel) {
case 'beta':
case 'canary':
return train ? `${train}-canary` : 'canary';
case 'beta':
return train ? `${train}-beta` : 'beta';
case 'lts':
return channel;
case 'release':
Expand All @@ -89,7 +112,11 @@ export function npmDistTagForChannelAndVersion(channel: CHANNEL, package_version
}
}

export function branchForChannelAndVersion(channel: CHANNEL, package_version: SEMVER_VERSION): VALID_BRANCHES {
export function branchForChannelAndVersion(
channel: CHANNEL,
package_version: SEMVER_VERSION,
train: VALID_TRAINS | ''
): VALID_BRANCHES {
const major = semver.major(package_version);
const minor = semver.minor(package_version);

Expand All @@ -103,8 +130,9 @@ export function branchForChannelAndVersion(channel: CHANNEL, package_version: SE

switch (channel) {
case 'canary':
return 'main';
return train ? `${train}-main` : 'main';
case 'beta':
return train ? `${train}-beta` : 'beta';
case 'release':
return channel;
case 'lts':
Expand Down
32 changes: 26 additions & 6 deletions release/utils/flags-config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HELP } from '../help/sections/manual';
import { ABOUT } from '../help/sections/about';
import { normalizeFlag, type CommandConfig, type FlagConfig } from './parse-args';
import { CHANNEL, SEMVER_VERSION, npmDistTagForChannelAndVersion } from './channel';
import { CHANNEL, SEMVER_VERSION, VALID_TRAINS, npmDistTagForChannelAndVersion } from './channel';
import { getGitState, getPublishedChannelInfo } from './git';
import chalk from 'chalk';
import semver from 'semver';
Expand Down Expand Up @@ -64,6 +64,15 @@ export const publish_flags_config: FlagConfig = {
description: 'Print this usage manual.',
examples: ['./publish/index.ts --help'],
},
train: {
name: 'Train',
flag: 'train',
type: String,
default_value: '',
description:
'The train from which publish if not the default. E.g. publish a new v4-canary from v4-main even though current major cycle is 5.x',
examples: ['./publish/index.ts canary --train=v4'],
},
channel: {
name: 'Channel',
flag: 'channel',
Expand Down Expand Up @@ -112,12 +121,14 @@ export const publish_flags_config: FlagConfig = {
examples: [],
default_value: async (options: Map<string, string | number | boolean | null>) => {
const gitInfo = await getGitState(options);
return npmDistTagForChannelAndVersion(gitInfo.expectedChannel, gitInfo.rootVersion);
const train = options.get('train') as VALID_TRAINS | '';
return npmDistTagForChannelAndVersion(gitInfo.expectedChannel, gitInfo.rootVersion, train);
},
validate: async (value: unknown, options: Map<string, string | number | boolean | null>) => {
const channel = options.get('channel') as CHANNEL;
const gitInfo = await getGitState(options);
const expectedTag = npmDistTagForChannelAndVersion(channel, gitInfo.rootVersion);
const train = options.get('train') as VALID_TRAINS | '';
const expectedTag = npmDistTagForChannelAndVersion(channel, gitInfo.rootVersion, train);
if (value !== expectedTag) {
if (!options.get('dangerously_force')) {
throw new Error(
Expand Down Expand Up @@ -238,7 +249,16 @@ export const publish_flags_config: FlagConfig = {
};

export const release_notes_flags_config: FlagConfig = merge(
pick(publish_flags_config, ['help', 'increment', 'dry_run', 'dangerously_force', 'tag', 'channel', 'upstream']),
pick(publish_flags_config, [
'help',
'train',
'increment',
'dry_run',
'dangerously_force',
'tag',
'channel',
'upstream',
]),
{
commit: {
name: 'Commit',
Expand Down Expand Up @@ -325,7 +345,7 @@ export const promote_flags_config: FlagConfig = merge(
if (existing.latest === version) {
return 'lts';
} else {
return npmDistTagForChannelAndVersion('lts-prev', version);
return npmDistTagForChannelAndVersion('lts-prev', version, '');
}
},
validate: async (value: unknown, options: Map<string, string | number | boolean | null>) => {
Expand All @@ -342,7 +362,7 @@ export const promote_flags_config: FlagConfig = merge(
throw new Error(`Expected a tag starting with "lts-" but got ${value}`);
}

const expected = npmDistTagForChannelAndVersion('lts-prev', version);
const expected = npmDistTagForChannelAndVersion('lts-prev', version, '');

if (expected !== value) {
throw new Error(`Expected tag lts or ${expected} for version ${version} but got ${value}`);
Expand Down
8 changes: 5 additions & 3 deletions release/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
npmDistTagForChannelAndVersion,
SEMVER_VERSION,
VALID_BRANCHES,
VALID_TRAINS,
} from './channel';
import { getFile } from './json-file';
import { exec } from './cmd';
Expand All @@ -24,7 +25,7 @@ export type CHANNEL_VERSIONS = {
beta: SEMVER_VERSION;
canary: SEMVER_VERSION;
lts: SEMVER_VERSION;
[key: LTS_TAG | RELEASE_TAG]: SEMVER_VERSION | undefined;
[key: LTS_TAG | RELEASE_TAG | `v${number}-${'beta' | 'canary'}`]: SEMVER_VERSION | undefined;
};

export type GIT_STATE = {
Expand Down Expand Up @@ -56,6 +57,7 @@ export async function getGitState(options: Map<string, boolean | string | number
}
const dangerously_force = options.get('dangerously_force') as boolean;
const isHelp = options.get('help') as boolean;
const train = options.get('train') as VALID_TRAINS | '';
const status = await exec(['git', 'status']);
let clean = true;
let current = true;
Expand Down Expand Up @@ -120,7 +122,7 @@ export async function getGitState(options: Map<string, boolean | string | number
const foundBranch = status.split('\n')[0].replace('On branch ', '');
const channel =
(options.get('channel') as CHANNEL) || channelForBranch(foundBranch, rootVersion, dangerously_force || isHelp);
const expectedBranch = branchForChannelAndVersion(channel, rootVersion);
const expectedBranch = branchForChannelAndVersion(channel, rootVersion, train);

if (foundBranch !== expectedBranch) {
if (dangerously_force || isHelp) {
Expand Down Expand Up @@ -213,7 +215,7 @@ export async function getAllPackagesForGitTag(tag: GIT_TAG): Promise<Map<string,

export async function pushLTSTagToRemoteBranch(tag: GIT_TAG, force?: boolean): Promise<void> {
const sha = await exec({ cmd: `git rev-list -n 1 ${tag}` });
const branch = npmDistTagForChannelAndVersion('lts-prev', tag.slice(1) as SEMVER_VERSION);
const branch = npmDistTagForChannelAndVersion('lts-prev', tag.slice(1) as SEMVER_VERSION, '');
let oldSha = '<none>';
try {
oldSha = await exec({ cmd: `git rev-list -n 1 refs/heads/${branch}` });
Expand Down

0 comments on commit 46406b1

Please sign in to comment.