Skip to content

Commit

Permalink
Create React sync automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Aug 26, 2024
1 parent b8a9ff7 commit 2df6d74
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 17 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/update_react.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Update React

on:
schedule:
# At 40 minutes past 16:00 on Mon, Tue, Wed, Thu, and Fri
# i.e. 30min past React nightlies: https://github.com/facebook/react/blob/941e1b4a0a81ca3d5f2ac6ef35682e2f8e96dae1/.github/workflows/runtime_prereleases_nightly.yml#L6
# TODO: automatically trigger on React release
- cron: 40 16 * * 1,2,3,4,5
# Allow manual runs
workflow_dispatch:
inputs:
version:
description: 'The version to update to. Uses latest Canary if omitted.'
required: false

env:
NODE_LTS_VERSION: 20

jobs:
create-pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Commits made with the default `GITHUB_TOKEN` won't trigger workflows.
# See: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#using-the-github_token-in-a-workflow
token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}

- name: Setup node
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_LTS_VERSION }}
check-latest: true

- run: corepack enable

- name: Install dependencies
shell: bash
run: pnpm i

- name: Create Pull Request
shell: bash
run: pnpm sync-react --actor "${{ github.actor }}" --version "${{ inputs.version }}" --create-pull
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
118 changes: 101 additions & 17 deletions scripts/sync-react.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ const yargs = require('yargs')
/** @type {any} */
const fetch = require('node-fetch')

const repoOwner = 'vercel'
const repoName = 'next.js'
const pullRequestLabels = ['type: react-sync']
const pullRequestReviewers = ['eps1lon']

const filesReferencingReactPeerDependencyVersion = [
'run-tests.js',
'packages/create-next-app/templates/index.ts',
Expand Down Expand Up @@ -155,9 +160,37 @@ async function main() {
const errors = []
const argv = await yargs(process.argv.slice(2))
.version(false)
.options('actor', {
type: 'string',
description:
'Required with `--create-pull`. The actor (GitHub username) that runs this script. Will be used for notifications but not commit attribution.',
})
.options('create-pull', {
default: false,
type: 'boolean',
description: 'Create a Pull Request in vercel/next.js',
})
.options('commit', {
default: true,
type: 'boolean',
description: 'Will not create any commit',
})
.options('install', { default: true, type: 'boolean' })
.options('version', { default: null, type: 'string' }).argv
const { install, version } = argv
const { actor, createPull, commit, install, version } = argv

if (createPull && !actor) {
throw new Error(
`Pull Request cannot be created without a GitHub actor (received '${String(actor)}'). ` +
'Pass an actor via `--actor "some-actor"`.'
)
}
const githubToken = process.env.GITHUB_TOKEN
if (createPull && !githubToken) {
throw new Error(
`Environment variable 'GITHUB_TOKEN' not specified but required when --create-pull is specified.`
)
}

let newVersionStr = version
if (newVersionStr === null) {
Expand Down Expand Up @@ -203,13 +236,21 @@ Or, run this command with no arguments to use the most recently published versio
noInstall: !install,
channel: 'experimental',
})
if (commit) {
await execa('git', ['add', '-A'])
await execa('git', ['commit', '--message', 'Update `react@experimental`'])
}
await sync({
newDateString,
newSha,
newVersionStr,
noInstall: !install,
channel: 'rc',
})
if (commit) {
await execa('git', ['add', '-A'])
await execa('git', ['commit', '--message', 'Update `react@rc`'])
}

const baseVersionInfo = extractInfoFromReactVersion(baseVersionStr)
if (!baseVersionInfo) {
Expand Down Expand Up @@ -269,6 +310,15 @@ Or, run this command with no arguments to use the most recently published versio
)
}

if (commit) {
await execa('git', ['add', '-A'])
await execa('git', [
'commit',
'--message',
'Updated peer dependency references',
])
}

// Install the updated dependencies and build the vendored React files.
if (!install) {
console.log('Skipping install step because --no-install flag was passed.\n')
Expand Down Expand Up @@ -300,34 +350,30 @@ Or, run this command with no arguments to use the most recently published versio
throw new Error('Failed to run ncc.')
}

if (commit) {
await execa('git', ['add', '-A'])
await execa('git', ['commit', '--message', 'ncc-compiled'])
}

// Print extra newline after ncc output
console.log()
}

console.log(
`**breaking change for canary users: Bumps peer dependency of React from \`${baseVersionStr}\` to \`${newVersionStr}\`**`
)
let prDescription = `**breaking change for canary users: Bumps peer dependency of React from \`${baseVersionStr}\` to \`${newVersionStr}\`**\n\n`

// Fetch the changelog from GitHub and print it to the console.
console.log(
`[diff facebook/react@${baseSha}...${newSha}](https://github.com/facebook/react/compare/${baseSha}...${newSha})`
)
prDescription += `[diff facebook/react@${baseSha}...${newSha}](https://github.com/facebook/react/compare/${baseSha}...${newSha})\n\n`
try {
const changelog = await getChangelogFromGitHub(baseSha, newSha)
if (changelog === null) {
console.log(
`GitHub reported no changes between ${baseSha} and ${newSha}.`
)
prDescription += `GitHub reported no changes between ${baseSha} and ${newSha}.`
} else {
console.log(
`<details>\n<summary>React upstream changes</summary>\n\n${changelog}\n\n</details>`
)
prDescription += `<details>\n<summary>React upstream changes</summary>\n\n${changelog}\n\n</details>`
}
} catch (error) {
console.error(error)
console.log(
prDescription +=
'\nFailed to fetch changelog from GitHub. Changes were applied, anyway.\n'
)
}

if (!install) {
Expand All @@ -343,13 +389,51 @@ Or run this command again without the --no-install flag to do both automatically
)
}

await fsp.writeFile(path.join(cwd, '.github/.react-version'), newVersionStr)

if (errors.length) {
// eslint-disable-next-line no-undef -- Defined in Node.js
throw new AggregateError(errors)
}

if (createPull) {
const github = await import('@actions/github')
const octokit = github.getOctokit(githubToken)
const branchName = `update/react/${newSha}-${newDateString}`

const pullRequest = await octokit.rest.pulls.create({
owner: repoOwner,
repo: repoName,
head: branchName,
base: 'main',
draft: false,
title: `Upgrade React from \`${baseSha}-${baseDateString}\` to \`${newSha}-${newDateString}\``,
body: prDescription,
})

await Promise.all([
actor
? octokit.rest.issues.addAssignees({
owner: repoOwner,
repo: repoName,
issue_number: pullRequest.data.number,
assignees: [actor],
})
: Promise.resolve(),
octokit.rest.pulls.requestReviewers({
owner: repoOwner,
repo: repoName,
pull_number: pullRequest.data.number,
reviewers: pullRequestReviewers,
}),
octokit.rest.issues.addLabels({
owner: repoOwner,
repo: repoName,
issue_number: pullRequest.data.number,
labels: pullRequestLabels,
}),
])
}

console.log(prDescription)
console.log(
`Successfully updated React from \`${baseSha}-${baseDateString}\` to \`${newSha}-${newDateString}\``
)
Expand Down

0 comments on commit 2df6d74

Please sign in to comment.