mirror of
https://github.com/facebook/lexical.git
synced 2025-08-06 16:39:33 +08:00
[*] Feature: Automated nightly releases (#6204)
This commit is contained in:
67
.github/workflows/call-increment-version.yml
vendored
Normal file
67
.github/workflows/call-increment-version.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
name: Increment Version
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
increment:
|
||||
required: true
|
||||
type: string
|
||||
dry-run:
|
||||
required: true
|
||||
type: boolean
|
||||
channel:
|
||||
required: true
|
||||
type: string
|
||||
git-repo:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
SSH_KEY:
|
||||
required: true
|
||||
outputs:
|
||||
version:
|
||||
description: 'The new package.json version, e.g. "0.16.0"'
|
||||
value: ${{ jobs.release.outputs.version }}
|
||||
tag-ref:
|
||||
description: 'The fully qualified ref for the tag, e.g. "refs/tags/v0.16.0"'
|
||||
value: ${{ jobs.release.outputs.tag-ref }}
|
||||
latest-release:
|
||||
description: 'The latest release (per GitHub releases) prior to this increment, e.g. "v0.15.0"'
|
||||
value: ${{ jobs.release.outputs.latest-release }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.increment-version.outputs.version }}
|
||||
tag-ref: ${{ steps.increment-version.outputs.tag-ref }}
|
||||
latest-release: ${{ steps.latest.outputs.release }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ssh-key: ${{ secrets.SSH_KEY }}
|
||||
fetch-depth: 0
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: |
|
||||
git config user.name "Lexical GitHub Actions Bot"
|
||||
git config user.email "<>"
|
||||
- id: latest
|
||||
uses: pozetroninc/github-action-get-latest-release@master
|
||||
with:
|
||||
owner: facebook
|
||||
repo: lexical
|
||||
excludes: draft
|
||||
- id: increment-version
|
||||
run: npm run increment-version
|
||||
env:
|
||||
# These are passed in the environment as they are used by
|
||||
# the postversion script
|
||||
INCREMENT: ${{ inputs.increment }}
|
||||
CHANNEL: ${{ inputs.channel }}
|
||||
LATEST_RELEASE: ${{ steps.latest.outputs.release }}
|
||||
DRY_RUN: ${{ inputs.dry-run && '1' || '' }}
|
||||
GIT_REPO: ${{ inputs.git-repo }}
|
36
.github/workflows/call-npm-publish.yml
vendored
Normal file
36
.github/workflows/call-npm-publish.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: (call) Publish to NPM
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ref:
|
||||
required: true
|
||||
type: string
|
||||
dry-run:
|
||||
required: true
|
||||
type: boolean
|
||||
channel:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
NPM_TOKEN:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DRY_RUN_ARG: ${{ inputs.dry-run && '--dry-run' || '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm run prepare-release
|
||||
- run: node ./scripts/npm/release.js --non-interactive $DRY_RUN_ARG --channel='${{ inputs.channel }}'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
42
.github/workflows/nightly-release.yml
vendored
42
.github/workflows/nightly-release.yml
vendored
@ -1,28 +1,26 @@
|
||||
name: Nightly Release Branch
|
||||
on:
|
||||
# remove the workflow_dispatch when this is turned on
|
||||
workflow_dispatch
|
||||
# Run daily at 2:30am UTC
|
||||
# schedule:
|
||||
# - cron: '30 2 * * 1-5'
|
||||
schedule:
|
||||
- cron: '30 2 * * 1-5'
|
||||
jobs:
|
||||
release:
|
||||
increment-version:
|
||||
# prevents this action from running on forks
|
||||
if: github.repository_owner == 'facebook'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ssh-key: ${{ secrets.SSH_KEY }}
|
||||
fetch-depth: 0
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: |
|
||||
git config user.name "Lexical GitHub Actions Bot"
|
||||
git config user.email "<>"
|
||||
- run: npm ci
|
||||
- run: npm run increment-version -- --i prerelease
|
||||
- run: git push -u git@github.com:facebook/lexical.git --follow-tags
|
||||
uses: ./.github/workflows/call-increment-version.yml
|
||||
with:
|
||||
channel: nightly
|
||||
increment: prerelease
|
||||
dry-run: false
|
||||
git-repo: 'git@github.com:facebook/lexical.git'
|
||||
secrets:
|
||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
||||
npm-release:
|
||||
uses: ./.github/workflows/call-npm-publish.yml
|
||||
needs: [increment-version]
|
||||
with:
|
||||
ref: ${{ needs.increment-version.outputs.tag-ref }}
|
||||
dry-run: false
|
||||
channel: nightly
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
20
.github/workflows/pre-release.yml
vendored
20
.github/workflows/pre-release.yml
vendored
@ -3,16 +3,10 @@ on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm run prepare-release
|
||||
- run: node ./scripts/npm/release.js --non-interactive --dry-run=${{ secrets.RELEASE_DRY_RUN }} --channel='latest'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
uses: ./.github/workflows/call-npm-publish.yml
|
||||
with:
|
||||
ref: main
|
||||
dry-run: false
|
||||
channel: latest
|
||||
secrets:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
34
.github/workflows/version.yml
vendored
34
.github/workflows/version.yml
vendored
@ -13,29 +13,11 @@ on:
|
||||
- minor
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ssh-key: ${{ secrets.SSH_KEY }}
|
||||
fetch-depth: 0
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: |
|
||||
git config user.name "Lexical GitHub Actions Bot"
|
||||
git config user.email "<>"
|
||||
- run: npm install
|
||||
- id: latest
|
||||
uses: pozetroninc/github-action-get-latest-release@master
|
||||
with:
|
||||
owner: facebook
|
||||
repo: lexical
|
||||
excludes: draft
|
||||
- run: LATEST_RELEASE=${{ steps.latest.outputs.release }} npm run increment-version -- --i $INCREMENT
|
||||
env:
|
||||
INCREMENT: ${{ inputs.increment }}
|
||||
- run: npm install
|
||||
- run: git push -u git@github.com:facebook/lexical.git --follow-tags
|
||||
uses: ./.github/workflows/call-increment-version.yml
|
||||
with:
|
||||
increment: ${{ inputs.increment }}
|
||||
dry-run: false
|
||||
channel: ${{ inputs.increment == 'prerelease' && 'next' || 'latest' }}
|
||||
git-repo: 'git@github.com:facebook/lexical.git'
|
||||
secrets:
|
||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
||||
|
@ -6,6 +6,7 @@
|
||||
!scripts/npm/**
|
||||
**/.output/**
|
||||
**/.browser-profiles/**
|
||||
!scripts/npm/**
|
||||
**/__tests__/integration/fixtures/**
|
||||
packages/**/.wxt/**
|
||||
packages/playwright
|
||||
|
@ -104,7 +104,7 @@
|
||||
"update-flowconfig": "node ./scripts/update-flowconfig",
|
||||
"create-www-stubs": "node ./scripts/create-www-stubs",
|
||||
"update-packages": "npm run update-version && npm run update-tsconfig && npm run update-flowconfig && npm run create-docs && npm run create-www-stubs",
|
||||
"postversion": "git checkout -b ${npm_package_version}__release && npm run update-version && npm install && npm run update-packages && npm run extract-codes && npm run update-changelog && git add -A && git commit -m v${npm_package_version} && git tag -a v${npm_package_version} -m v${npm_package_version}",
|
||||
"postversion": "node ./scripts/npm/postversion",
|
||||
"publish-extension": "npm run zip -w @lexical/devtools && npm run publish -w @lexical/devtools",
|
||||
"release": "npm run prepare-release && node ./scripts/npm/release.js",
|
||||
"size": "npm run build-prod && size-limit"
|
||||
|
@ -258,7 +258,7 @@ The postversion script will:
|
||||
- Create a version commit and tag from the branch
|
||||
|
||||
This is typically executed through the `version.yml` GitHub Workflow which
|
||||
will also push the tag.
|
||||
will also push the tag and branch.
|
||||
|
||||
### npm run changelog
|
||||
|
||||
@ -270,3 +270,20 @@ Update the changelog from git history.
|
||||
plus creating a tag in git, and likely other steps.
|
||||
|
||||
Runs prepare-release to do a full build and then uploads to npm.
|
||||
|
||||
## Release Procedure
|
||||
|
||||
This is the current release procedure for public releases, at least as of
|
||||
May 2024 (~0.15.0).
|
||||
|
||||
The main branch should be "frozen" during this procedure (no other PRs should
|
||||
be merged during this time). This avoids a mismatch between the contents of
|
||||
the GitHub release (created from main in step 1) and the NPM release (created
|
||||
from main in step 4).
|
||||
|
||||
1. Create a new version with the Github Actions "Create New Release Branch" workflow (`version.yml`)
|
||||
2. Raise a PR against version branch created by that action
|
||||
3. After PR is approved with passing tests, merge PR
|
||||
4. After PR is merged to main, publish to NPM with the Github Actions "Publish to NPM" workflow (`pre-release.yml`)
|
||||
5. Create a GitHub release from the tag created in step 1, manually editing the release notes
|
||||
6. Announce the release in #announcements on Discord
|
||||
|
@ -10,21 +10,57 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const {exec} = require('child-process-promise');
|
||||
const {spawn} = require('child-process-promise');
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
|
||||
const increment = argv.i;
|
||||
const validIncrements = new Set(['minor', 'patch', 'prerelease']);
|
||||
if (!validIncrements.has(increment)) {
|
||||
console.error(`Invalid value for increment: ${increment}`);
|
||||
const increment = argv.i || process.env.INCREMENT;
|
||||
const channel = argv.channel || process.env.CHANNEL;
|
||||
|
||||
const validChannels = new Set(['next', 'latest', 'nightly', 'dev']);
|
||||
if (!validChannels.has(channel)) {
|
||||
console.error(`Invalid value for channel: ${channel}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const validIncrements = new Set(['minor', 'patch', 'prerelease']);
|
||||
if (
|
||||
!validIncrements.has(increment) ||
|
||||
(channel === 'nightly' && increment !== 'prerelease')
|
||||
) {
|
||||
console.error(
|
||||
`Invalid value for increment in ${channel} channel: ${increment}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function incrementArgs() {
|
||||
return [
|
||||
...(increment === 'prerelease'
|
||||
? [
|
||||
'--preid',
|
||||
channel === 'nightly'
|
||||
? `${channel}.${new Date()
|
||||
.toISOString()
|
||||
.split('T')[0]
|
||||
.replaceAll('-', '')}`
|
||||
: channel,
|
||||
]
|
||||
: []),
|
||||
increment,
|
||||
];
|
||||
}
|
||||
|
||||
async function incrementVersion() {
|
||||
const preId = increment === 'prerelease' ? '--preid next' : '';
|
||||
const workspaces = '';
|
||||
const command = `npm --no-git-tag-version version ${increment} --include-workspace-root true ${preId} ${workspaces}`;
|
||||
await exec(command);
|
||||
const commandArr = [
|
||||
'npm',
|
||||
'version',
|
||||
'--no-git-tag-version',
|
||||
'--include-workspace-root',
|
||||
'true',
|
||||
...incrementArgs(),
|
||||
];
|
||||
console.log(commandArr.join(' '));
|
||||
await spawn(commandArr[0], commandArr.slice(1), {stdio: 'inherit'});
|
||||
}
|
||||
|
||||
incrementVersion();
|
||||
|
97
scripts/npm/postversion.js
Normal file
97
scripts/npm/postversion.js
Normal file
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const {spawn} = require('child-process-promise');
|
||||
|
||||
const {npm_package_version, CHANNEL, GIT_REPO, GITHUB_OUTPUT} = process.env;
|
||||
|
||||
// Previously this script was defined directly in package.json as the
|
||||
// following (in one line):
|
||||
//
|
||||
// git checkout -b ${npm_package_version}__release && \
|
||||
// npm run update-version && \
|
||||
// npm install && \
|
||||
// npm run update-packages && \
|
||||
// npm run extract-codes && \
|
||||
// npm run update-changelog && \
|
||||
// git add -A && \
|
||||
// git commit -m v${npm_package_version} && \
|
||||
// git tag -a v${npm_package_version} -m v${npm_package_version}
|
||||
//
|
||||
async function main() {
|
||||
// CHANNEL should already be validated by increment-version which calls this (indirectly)
|
||||
for (const [k, v] of Object.entries({
|
||||
CHANNEL,
|
||||
GIT_REPO,
|
||||
npm_package_version,
|
||||
})) {
|
||||
if (!v) {
|
||||
console.error(`Expecting ${k} to be set in the environment`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
const commands = [
|
||||
// Create or force update the channel branch to build the docs site from
|
||||
['git', 'checkout', '-B', `${CHANNEL}__release`],
|
||||
// Update all package.json versions in the monorepo
|
||||
`npm run update-version`,
|
||||
// Update package-lock.json
|
||||
`npm install`,
|
||||
// Fix up all package.json files
|
||||
`npm run update-packages`,
|
||||
// Extract error codes and update changelog, but only in production
|
||||
...(CHANNEL === 'latest'
|
||||
? [`npm run extract-codes`, `npm run update-changelog`]
|
||||
: []),
|
||||
`git add -A`,
|
||||
['git', 'commit', '-m', `v${npm_package_version}`],
|
||||
[
|
||||
'git',
|
||||
'tag',
|
||||
'-a',
|
||||
`v${npm_package_version}`,
|
||||
'-m',
|
||||
`v${npm_package_version}`,
|
||||
],
|
||||
];
|
||||
const refs = [
|
||||
`refs/tags/v${npm_package_version}`,
|
||||
`refs/heads/${CHANNEL}__release`,
|
||||
];
|
||||
if (CHANNEL !== 'nightly') {
|
||||
// Create or force update the remote version branch for creating a PR
|
||||
refs.push(
|
||||
`refs/heads/${CHANNEL}__release:refs/heads/${npm_package_version}__release`,
|
||||
);
|
||||
}
|
||||
commands.push([
|
||||
'git',
|
||||
'push',
|
||||
...(process.env.DRY_RUN === '1' ? ['--dry-run'] : []),
|
||||
GIT_REPO,
|
||||
...refs.map((ref) => `+${ref}`),
|
||||
]);
|
||||
if (GITHUB_OUTPUT) {
|
||||
commands.push(
|
||||
`echo "version=${npm_package_version}" >> '${GITHUB_OUTPUT}'`,
|
||||
);
|
||||
commands.push(`echo "tag-ref=${refs[0]}" >> '${GITHUB_OUTPUT}'`);
|
||||
}
|
||||
for (const command of commands) {
|
||||
const commandArr = Array.isArray(command)
|
||||
? command
|
||||
: ['bash', '-c', command];
|
||||
console.log(commandArr.join(' '));
|
||||
await spawn(commandArr[0], commandArr.slice(1), {stdio: 'inherit'});
|
||||
}
|
||||
}
|
||||
main();
|
Reference in New Issue
Block a user