mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Publish React Compiler to open source
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
name: Commit Artifacts for Meta WWW and fbsource
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, meta-www, meta-fbsource]
|
||||
|
||||
jobs:
|
||||
download_artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
www_branch_count: ${{ steps.check_branches.outputs.www_branch_count }}
|
||||
fbsource_branch_count: ${{ steps.check_branches.outputs.fbsource_branch_count }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Check branches"
|
||||
id: check_branches
|
||||
run: |
|
||||
echo "www_branch_count=$(git ls-remote --heads origin "refs/heads/meta-www" | wc -l)" >> "$GITHUB_OUTPUT"
|
||||
echo "fbsource_branch_count=$(git ls-remote --heads origin "refs/heads/meta-fbsource" | wc -l)" >> "$GITHUB_OUTPUT"
|
||||
- name: Download and unzip artifacts
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
CIRCLECI_TOKEN: ${{secrets.CIRCLECI_TOKEN_DIFFTRAIN}}
|
||||
with:
|
||||
script: |
|
||||
const cp = require('child_process');
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function execHelper(command, options, streamStdout = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = cp.exec(
|
||||
command,
|
||||
options,
|
||||
(error, stdout) => (error ? reject(error) : resolve(stdout.trim())),
|
||||
);
|
||||
if (streamStdout) {
|
||||
proc.stdout.pipe(process.stdout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let artifactsUrl = null;
|
||||
// This is a temporary, dirty hack to avoid needing a GitHub auth token in the circleci
|
||||
// workflow to notify this GitHub action. Sorry!
|
||||
let iter = 0;
|
||||
spinloop: while (iter < 15) {
|
||||
const res = await github.rest.repos.listCommitStatusesForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: context.sha
|
||||
});
|
||||
for (const status of res.data) {
|
||||
if (/process_artifacts_combined/.test(status.context)) {
|
||||
switch (status.state) {
|
||||
case 'pending': {
|
||||
console.log(`${status.context} is still pending`);
|
||||
break;
|
||||
}
|
||||
case 'failure':
|
||||
case 'error': {
|
||||
throw new Error(`${status.context} has failed or errored`);
|
||||
}
|
||||
case 'success': {
|
||||
// The status does not include a build ID, but we can extract it
|
||||
// from the URL. I couldn't find a better way to do this.
|
||||
const ciBuildId = /\/facebook\/react\/([0-9]+)/.exec(
|
||||
status.target_url,
|
||||
)[1];
|
||||
if (Number.parseInt(ciBuildId, 10) + '' === ciBuildId) {
|
||||
artifactsUrl =
|
||||
`https://circleci.com/api/v1.1/project/github/facebook/react/${ciBuildId}/artifacts`;
|
||||
console.log(`Found artifactsUrl: ${artifactsUrl}`);
|
||||
break spinloop;
|
||||
} else {
|
||||
throw new Error(`${ciBuildId} isn't a number`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unhandled status state: ${status.state}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
console.log("Sleeping for 60s...");
|
||||
await sleep(60_000);
|
||||
}
|
||||
if (artifactsUrl != null) {
|
||||
const {CIRCLECI_TOKEN} = process.env;
|
||||
const res = await fetch(artifactsUrl, {
|
||||
headers: {
|
||||
'Circle-Token': CIRCLECI_TOKEN
|
||||
}
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!Array.isArray(data) && data.message != null) {
|
||||
throw `CircleCI returned: ${data.message}`;
|
||||
}
|
||||
for (const artifact of data) {
|
||||
if (artifact.path === 'build.tgz') {
|
||||
console.log(`Downloading and unzipping ${artifact.url}`);
|
||||
await execHelper(
|
||||
`curl -L ${artifact.url} -H "Circle-Token: ${CIRCLECI_TOKEN}" | tar -xvz`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
- name: Strip @license from eslint plugin and react-refresh
|
||||
run: |
|
||||
sed -i -e 's/ @license React*//' \
|
||||
build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
|
||||
build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js
|
||||
- name: Move relevant files for React in www into compiled
|
||||
run: |
|
||||
# Move the facebook-www folder into compiled
|
||||
mkdir ./compiled
|
||||
mv build/facebook-www ./compiled
|
||||
|
||||
# Move ReactAllWarnings.js to facebook-www
|
||||
mkdir ./compiled/facebook-www/__test_utils__
|
||||
mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js
|
||||
|
||||
# Move eslint-plugin-react-hooks into facebook-www
|
||||
mv build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \
|
||||
./compiled/facebook-www/eslint-plugin-react-hooks.js
|
||||
|
||||
# Move unstable_server-external-runtime.js into facebook-www
|
||||
mv build/oss-experimental/react-dom/unstable_server-external-runtime.js \
|
||||
./compiled/facebook-www/unstable_server-external-runtime.js
|
||||
|
||||
# Move react-refresh-babel.development.js into babel-plugin-react-refresh
|
||||
mkdir ./compiled/babel-plugin-react-refresh
|
||||
mv build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js \
|
||||
./compiled/babel-plugin-react-refresh/index.js
|
||||
|
||||
ls -R ./compiled
|
||||
- name: Move relevant files for React in fbsource into compiled-rn
|
||||
run: |
|
||||
BASE_FOLDER='compiled-rn/facebook-fbsource/xplat/js'
|
||||
mkdir -p ${BASE_FOLDER}/react-native-github/Libraries/Renderer/
|
||||
mkdir -p ${BASE_FOLDER}/RKJSModules/vendor/react/{scheduler,react,react-is,react-test-renderer}/
|
||||
|
||||
# Move React Native renderer
|
||||
mv build/react-native/implementations/ $BASE_FOLDER/react-native-github/Libraries/Renderer/
|
||||
mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/
|
||||
mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/
|
||||
mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/
|
||||
mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/
|
||||
mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/
|
||||
|
||||
# Delete OSS renderer. OSS renderer is synced through internal script.
|
||||
RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/
|
||||
rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js
|
||||
rm $RENDERER_FOLDER/ReactNativeRenderer-{dev,prod,profiling}.js
|
||||
|
||||
ls -R ./compiled
|
||||
- name: Add REVISION file
|
||||
run: |
|
||||
echo ${{ github.sha }} >> ./compiled/facebook-www/REVISION
|
||||
echo ${{ github.sha }} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: compiled
|
||||
path: compiled/
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: compiled-rn
|
||||
path: compiled-rn/
|
||||
|
||||
commit_www_artifacts:
|
||||
needs: download_artifacts
|
||||
if: ${{ (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.www_branch_count == '0') || github.ref == 'refs/heads/meta-www' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: builds/facebook-www
|
||||
- name: Ensure clean directory
|
||||
run: rm -rf compiled
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: compiled
|
||||
path: compiled/
|
||||
- run: git status -u
|
||||
- name: Check if only the REVISION file has changed
|
||||
id: check_should_commit
|
||||
run: |
|
||||
if git status --porcelain | grep -qv '/REVISION$'; then
|
||||
echo "should_commit=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "should_commit=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Commit changes to branch
|
||||
if: steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.head_commit.message }}
|
||||
|
||||
DiffTrain build for [${{ github.sha }}](https://github.com/facebook/react/commit/${{ github.sha }})
|
||||
branch: builds/facebook-www
|
||||
commit_user_name: ${{ github.actor }}
|
||||
commit_user_email: ${{ github.actor }}@users.noreply.github.com
|
||||
create_branch: true
|
||||
|
||||
commit_fbsource_artifacts:
|
||||
needs: download_artifacts
|
||||
if: ${{ (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.fbsource_branch_count == '0') || github.ref == 'refs/heads/meta-fbsource' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: builds/facebook-fbsource
|
||||
- name: Ensure clean directory
|
||||
run: rm -rf compiled
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: compiled-rn
|
||||
path: compiled-rn/
|
||||
- run: git status -u
|
||||
- name: Check if only the REVISION file has changed
|
||||
id: check_should_commit
|
||||
run: |
|
||||
if git status --porcelain | grep -qv '/REVISION$'; then
|
||||
echo "should_commit=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "should_commit=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Commit changes to branch
|
||||
if: steps.check_should_commit.outputs.should_commit == 'true'
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
commit_message: |
|
||||
${{ github.event.head_commit.message }}
|
||||
|
||||
DiffTrain build for commit https://github.com/facebook/react/commit/${{ github.sha }}.
|
||||
branch: builds/facebook-fbsource
|
||||
commit_user_name: ${{ github.actor }}
|
||||
commit_user_email: ${{ github.actor }}@users.noreply.github.com
|
||||
create_branch: true
|
||||
@@ -0,0 +1,205 @@
|
||||
name: DevTools Check for bug repro
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
jobs:
|
||||
check-repro:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const URL_REGEXP = /### Website or app[\r\n]+([^#]+)###/m;
|
||||
const REPRO_STEPS_REGEXP = /### Repro steps[\r\n]+([^#]+)###/m;
|
||||
const LABEL_NEEDS_MORE_INFORMATION = "Resolution: Needs More Information";
|
||||
const LABEL_UNCONFIRMED = "Status: Unconfirmed";
|
||||
|
||||
function debug(...args) {
|
||||
core.info(args.map(JSON.stringify).join(' '));
|
||||
}
|
||||
|
||||
if (context.payload.comment) {
|
||||
debug('Ignoring comment update.');
|
||||
return;
|
||||
}
|
||||
|
||||
const user = context.payload.sender.login;
|
||||
const issue = context.payload.issue;
|
||||
const body = issue.body;
|
||||
|
||||
const urlMatch = body.match(URL_REGEXP);
|
||||
const reproStepsMatch = body.match(REPRO_STEPS_REGEXP);
|
||||
|
||||
const url = urlMatch !== null ? urlMatch[1].trim() : null;
|
||||
const reproSteps = reproStepsMatch !== null ? reproStepsMatch[1].trim() : null;
|
||||
|
||||
if (!url || !reproSteps) {
|
||||
debug('This issue is not a DevTools bug report.');
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`found URL "${url}"`);
|
||||
debug(`found repro steps "${reproSteps}"`);
|
||||
|
||||
async function createComment(comment) {
|
||||
// Format
|
||||
comment = comment
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.join("\n")
|
||||
.trim();
|
||||
|
||||
await github.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment,
|
||||
});
|
||||
}
|
||||
|
||||
async function getGitHubActionComments() {
|
||||
debug(`Loading existing comments...`);
|
||||
|
||||
const comments = await github.issues.listComments({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
return comments.data.filter(comment => {
|
||||
debug(`comment by user: "${comment.user.login}"`);
|
||||
return comment.user.login === 'github-actions[bot]';
|
||||
});
|
||||
}
|
||||
|
||||
async function getIssueLabels() {
|
||||
const issues = await github.issues.listLabelsOnIssue({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
return issues.data;
|
||||
}
|
||||
|
||||
async function updateIssue(state, assignees = []) {
|
||||
await github.issues.update({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state,
|
||||
assignees,
|
||||
});
|
||||
}
|
||||
|
||||
async function closeWithComment(comment) {
|
||||
if (issue.state !== 'open') {
|
||||
debug(`Issue is not open`);
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = await getIssueLabels();
|
||||
const label = labels.find(label => label.name === LABEL_UNCONFIRMED);
|
||||
if (!label) {
|
||||
debug(`Issue was not opened via DevTools bug report template`);
|
||||
return;
|
||||
}
|
||||
|
||||
const comments = await getGitHubActionComments();
|
||||
if (comments.length > 0) {
|
||||
debug(`Already commented on issue; won't comment again`);
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`Missing required information`);
|
||||
|
||||
await github.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: [LABEL_NEEDS_MORE_INFORMATION],
|
||||
});
|
||||
|
||||
await createComment(comment);
|
||||
await updateIssue('closed', [user]);
|
||||
}
|
||||
|
||||
async function openWithComment(comment) {
|
||||
if (issue.state !== 'closed') {
|
||||
debug(`Issue is already open`);
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = await getIssueLabels();
|
||||
const label = labels.find(label => label.name === LABEL_NEEDS_MORE_INFORMATION);
|
||||
if (!label) {
|
||||
debug(`Issue was not tagged as needs information`);
|
||||
return;
|
||||
}
|
||||
|
||||
const comments = await getGitHubActionComments();
|
||||
if (comments.length === 0) {
|
||||
debug(`Issue was closed by someone else; won't reopen`);
|
||||
return;
|
||||
}
|
||||
|
||||
debug(`Re-opening closed issue`);
|
||||
|
||||
await github.issues.removeLabel({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: LABEL_NEEDS_MORE_INFORMATION,
|
||||
});
|
||||
|
||||
await createComment(comment);
|
||||
await updateIssue('open');
|
||||
}
|
||||
|
||||
const PROBABLY_NOT_A_URL_REGEX = /(^Chrome$|^Firefox$| Website)/i;
|
||||
|
||||
const COMMENT_HEADER = `
|
||||
@${user}: We're sorry you've seen this error. ❤️
|
||||
`.trim();
|
||||
|
||||
const COMMENT_FOOTER = `
|
||||
Please help us by providing a link to a CodeSandbox (https://codesandbox.io/s/new), a repository on GitHub, or a minimal code example that reproduces the problem. (Screenshots or videos can also be helpful if they help provide context on how to repro the bug.)
|
||||
|
||||
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve
|
||||
|
||||
Issues without repros are automatically closed but we will re-open if you update with repro info.
|
||||
`.trim();
|
||||
|
||||
if (url.includes("localhost")) {
|
||||
closeWithComment(`
|
||||
${COMMENT_HEADER}
|
||||
|
||||
Unfortunately the URL you provided ("localhost") is not publicly accessible. (This means that we will not be able to reproduce the problem you're reporting.)
|
||||
|
||||
${COMMENT_FOOTER}
|
||||
`);
|
||||
} else if (url.length < 10 || url.match(PROBABLY_NOT_A_URL_REGEX)) {
|
||||
closeWithComment(`
|
||||
${COMMENT_HEADER}
|
||||
|
||||
It looks like you forgot to specify a valid URL. (This means that we will not be able to reproduce the problem you're reporting.)
|
||||
|
||||
${COMMENT_FOOTER}
|
||||
`);
|
||||
} else if (reproSteps.length < 25) {
|
||||
closeWithComment(`
|
||||
${COMMENT_HEADER}
|
||||
|
||||
Unfortunately, it doesn't look like this issue has enough info for one of us to reproduce and fix it though.
|
||||
|
||||
${COMMENT_FOOTER}
|
||||
`);
|
||||
} else {
|
||||
openWithComment(`
|
||||
Thank you for providing repro steps! Re-opening issue now for triage.
|
||||
`);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
name: facebook/react/fuzz_tests
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 * * * *
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
prerelease_commit_sha:
|
||||
required: false
|
||||
jobs:
|
||||
test_fuzz:
|
||||
if: inputs.prerelease_commit_sha == ''
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TZ: "/usr/share/zoneinfo/America/Los_Angeles"
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
env:
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: "1"
|
||||
shell: bash
|
||||
- name: Run fuzz tests
|
||||
run: |-
|
||||
FUZZ_TEST_SEED=$RANDOM yarn test fuzz --ci
|
||||
FUZZ_TEST_SEED=$RANDOM yarn test --prod fuzz --ci
|
||||
@@ -0,0 +1,46 @@
|
||||
# Configuration for stale action workflow - https://github.com/actions/stale
|
||||
name: 'Manage stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
# Run hourly
|
||||
- cron: '0 * * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
# --- Issues & PRs ---
|
||||
# Number of days of inactivity before an issue or PR becomes stale
|
||||
days-before-stale: 90
|
||||
# Number of days of inactivity before a stale issue or PR is closed
|
||||
days-before-close: 7
|
||||
# API calls per run
|
||||
operations-per-run: 100
|
||||
|
||||
# --- Issues ---
|
||||
stale-issue-label: "Resolution: Stale"
|
||||
# Comment to post when marking an issue as stale
|
||||
stale-issue-message: >
|
||||
This issue has been automatically marked as stale.
|
||||
**If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open.
|
||||
We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
|
||||
# Comment to post when closing a stale issue
|
||||
close-issue-message: >
|
||||
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!
|
||||
# Issues with these labels will never be considered stale
|
||||
exempt-issue-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement"
|
||||
|
||||
# --- PRs ---
|
||||
stale-pr-label: "Resolution: Stale"
|
||||
# Comment to post when marking a pull request as stale
|
||||
stale-pr-message: >
|
||||
This pull request has been automatically marked as stale.
|
||||
**If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open.
|
||||
We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated.
|
||||
# Comment to post when closing a stale pull request
|
||||
close-pr-message: >
|
||||
Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you!
|
||||
# PRs with these labels will never be considered stale
|
||||
exempt-pr-labels: "Partner,React Core Team,Resolution: Backlog,Type: Bug,Type: Discussion,Type: Needs Investigation,Type: Regression,Type: Feature Request,Type: Enhancement"
|
||||
Reference in New Issue
Block a user