mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
b6f269e8a3
Summary:
This PR does two things:
1. Improves the labeling workflow in cases where the user is on a supported version but a higher patch number is available. Now, the label name will be friendlier ('Newer Patch Available') and we will report the version they should consider upgrading to in the message body. Once this change is merged, I can also rename all existing versions of this label for consistency.
2. Moves the addDescriptiveLabels.js script to the workflow-scripts folder for consistency with the other workflow scripts.
## Changelog:
[INTERNAL] [CHANGED] - Enhancing issue triage workflow for patch versioning
Pull Request resolved: https://github.com/facebook/react-native/pull/37324
Test Plan: See some examples of the workflow run in my fork: https://github.com/SlyCaptainFlint/react-native/issues
Reviewed By: cipolleschi
Differential Revision: D45680812
Pulled By: NickGerleman
fbshipit-source-id: 7ab07fcf52fe372d2e449bb43d6618b1c98e9245
121 lines
3.9 KiB
JavaScript
121 lines
3.9 KiB
JavaScript
/**
|
|
* 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.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
module.exports = async (github, context) => {
|
|
const issue = context.payload.issue;
|
|
|
|
// Ignore issues using upgrade template (they use a special label)
|
|
if (issue.labels.find(label => label.name == 'Type: Upgrade Issue')) {
|
|
return;
|
|
}
|
|
|
|
const issueVersionUnparsed =
|
|
getReactNativeVersionFromIssueBodyIfExists(issue);
|
|
const issueVersion = parseVersionFromString(issueVersionUnparsed);
|
|
|
|
// Nightly versions are always supported
|
|
if (reportedVersionIsNightly(issueVersionUnparsed, issueVersion)) return;
|
|
|
|
if (!issueVersion) {
|
|
return {label: 'Needs: Version Info'};
|
|
}
|
|
|
|
// Ensure the version matches one we support
|
|
const recentReleases = (
|
|
await github.rest.repos.listReleases({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
})
|
|
).data.map(release => release.name);
|
|
|
|
const latestRelease = (
|
|
await github.rest.repos.getLatestRelease({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
})
|
|
).data;
|
|
const latestVersion = parseVersionFromString(latestRelease.name);
|
|
|
|
if (!isVersionSupported(issueVersion, latestVersion)) {
|
|
return {label: 'Type: Unsupported Version'};
|
|
}
|
|
|
|
// We want to encourage users to repro the issue on the highest available patch for the given minor.
|
|
const latestPatchForVersion = getLatestPatchForVersion(
|
|
issueVersion,
|
|
recentReleases,
|
|
);
|
|
if (latestPatchForVersion > issueVersion.patch) {
|
|
return {
|
|
label: 'Newer Patch Available',
|
|
newestPatch: `${issueVersion.major}.${issueVersion.minor}.${latestPatchForVersion}`,
|
|
};
|
|
}
|
|
};
|
|
|
|
// We support N-2 minor versions, and the latest major.
|
|
function isVersionSupported(actualVersion, latestVersion) {
|
|
return (
|
|
actualVersion.major >= latestVersion.major &&
|
|
actualVersion.minor >= latestVersion.minor - 2
|
|
);
|
|
}
|
|
|
|
// Assumes that releases are sorted in the order of recency (i.e. most recent releases are earlier in the list)
|
|
// This enables us to stop looking as soon as we find the first release with a matching major/minor version, since
|
|
// we know it's the most recent release, therefore the highest patch available.
|
|
function getLatestPatchForVersion(version, releases) {
|
|
for (releaseName of releases) {
|
|
const release = parseVersionFromString(releaseName);
|
|
if (
|
|
release &&
|
|
release.major == version.major &&
|
|
release.minor == version.minor
|
|
) {
|
|
return release.patch;
|
|
}
|
|
}
|
|
}
|
|
|
|
function getReactNativeVersionFromIssueBodyIfExists(issue) {
|
|
if (!issue || !issue.body) return;
|
|
const rnVersionRegex = /React Native Version[\r\n]+(?<version>.+)[\r\n]*/;
|
|
const rnVersionMatch = issue.body.match(rnVersionRegex);
|
|
if (!rnVersionMatch || !rnVersionMatch.groups.version) return;
|
|
return rnVersionMatch.groups.version;
|
|
}
|
|
|
|
function reportedVersionIsNightly(unparsedVersionString, version) {
|
|
if (!unparsedVersionString && !version) return false;
|
|
const nightlyRegex = /nightly/i;
|
|
const nightlyMatch = unparsedVersionString.match(nightlyRegex);
|
|
const versionIsNightly = nightlyMatch && nightlyMatch[0];
|
|
|
|
const versionIsZero =
|
|
version && version.major == 0 && version.minor == 0 && version.patch == 0;
|
|
|
|
return versionIsZero || versionIsNightly;
|
|
}
|
|
|
|
function parseVersionFromString(version) {
|
|
if (!version) return;
|
|
// This will match the standard x.x.x semver format, as well as the non-standard prerelease x.x.x-rc.x
|
|
const semverRegex =
|
|
/(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(-[rR]{1}[cC]{1}\.(?<prerelease>\d+))?/;
|
|
const versionMatch = version.match(semverRegex);
|
|
if (!versionMatch) return;
|
|
const {major, minor, patch, prerelease} = versionMatch.groups;
|
|
return {
|
|
major: parseInt(major),
|
|
minor: parseInt(minor),
|
|
patch: parseInt(patch),
|
|
prerelease: parseInt(prerelease),
|
|
};
|
|
}
|