-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(react-native-github): a script to automate patch version bumping of packages #35767
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat(react-native-github): a script to automate patch version bumping…
… of packages (#35767) Summary: Pull Request resolved: #35767 Changelog: [Internal] Introducing a script, which can be used to identify all packages inside `/packages`, which contain any changes after the last time its version was changed How it works step by step: ``` check that no git changes are present for each package: if package is private -> skip grep id of the last commit that changed package grep id of the last commit that changed version of the package if these ids are different: bump package patch version commit changes if required ``` Can be executed only in git environment and by running: `node ./scripts/bump-all-updated-packages` --- Also adding a separate script `align-package-versions.js`, which can be used to update versions of packages inside consumer packages ``` check that no git changes are present for each package x: for each package y: if y has x as dependency: validate that y uses the latest version of x if some changes were made: run yarn ``` --- Q: Why `run_yarn` step was removed from CircleCI flow? A: For *-stable branches, there are no yarn workspaces and all packages are specified as direct dependencies, so if we update `react-native/assets-registry` to the next version, we won't be able to run `yarn` for react-native root package, because updated version is not yet published to npm To avoid this, we first need publish new versions and then update them in consumer packages --- The final flow: 1. Developer uses `node ./scripts/bump-all-updated-packages` to bump versions of all updated packages. 2. Commit created from step 1 being merged or directly pushed to `main` or `*-stable` branches 3. A workflow from CircleCI publishes all updated versions to npm 4. Developer can use `align-package-versions.js` script to create required changes to align all packages versions Reviewed By: cortinico Differential Revision: D42295344 fbshipit-source-id: 1a4bbe33a996a93af37a6642ed4a11341066e6ee
- Loading branch information
commit 104a05f024e23054ad916141af8eb06db468c47b
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* 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 | ||
*/ | ||
|
||
const path = require('path'); | ||
const {writeFileSync} = require('fs'); | ||
|
||
const bumpPackageVersion = require('../bump-all-updated-packages/bump-package-version'); | ||
|
||
jest.mock('fs', () => ({ | ||
writeFileSync: jest.fn(), | ||
readFileSync: jest.fn(() => '{}'), | ||
})); | ||
|
||
jest.mock('../for-each-package', () => callback => {}); | ||
|
||
describe('bumpPackageVersionTest', () => { | ||
it('updates patch version of the package', () => { | ||
const mockedPackageLocation = '~/packages/assets'; | ||
const mockedPackageManifest = { | ||
name: '@react-native/test', | ||
version: '1.2.3', | ||
}; | ||
|
||
bumpPackageVersion(mockedPackageLocation, mockedPackageManifest); | ||
|
||
expect(writeFileSync).toHaveBeenCalledWith( | ||
path.join(mockedPackageLocation, 'package.json'), | ||
JSON.stringify({...mockedPackageManifest, version: '1.2.4'}, null, 2) + | ||
'\n', | ||
'utf-8', | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** | ||
* 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 | ||
*/ | ||
|
||
const {spawnSync} = require('child_process'); | ||
const {writeFileSync, readFileSync} = require('fs'); | ||
const path = require('path'); | ||
|
||
const checkForGitChanges = require('./check-for-git-changes'); | ||
const forEachPackage = require('./for-each-package'); | ||
|
||
const ROOT_LOCATION = path.join(__dirname, '..', '..'); | ||
const TEMPLATE_LOCATION = path.join(ROOT_LOCATION, 'template'); | ||
const REPO_CONFIG_LOCATION = path.join(ROOT_LOCATION, 'repo-config'); | ||
|
||
const readJSONFile = pathToFile => JSON.parse(readFileSync(pathToFile)); | ||
|
||
const checkIfShouldUpdateDependencyPackageVersion = ( | ||
consumerPackageAbsolutePath, | ||
updatedPackageName, | ||
updatedPackageVersion, | ||
) => { | ||
const consumerPackageManifestPath = path.join( | ||
consumerPackageAbsolutePath, | ||
'package.json', | ||
); | ||
const consumerPackageManifest = readJSONFile(consumerPackageManifestPath); | ||
|
||
const dependencyVersion = | ||
consumerPackageManifest.dependencies?.[updatedPackageName]; | ||
|
||
if (dependencyVersion && dependencyVersion !== '*') { | ||
const updatedDependencyVersion = dependencyVersion.startsWith('^') | ||
? `^${updatedPackageVersion}` | ||
: updatedPackageVersion; | ||
|
||
if (updatedDependencyVersion !== dependencyVersion) { | ||
console.log( | ||
`\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`, | ||
); | ||
|
||
const updatedPackageManifest = { | ||
...consumerPackageManifest, | ||
dependencies: { | ||
...consumerPackageManifest.dependencies, | ||
[updatedPackageName]: updatedDependencyVersion, | ||
}, | ||
}; | ||
|
||
writeFileSync( | ||
consumerPackageManifestPath, | ||
JSON.stringify(updatedPackageManifest, null, 2) + '\n', | ||
'utf-8', | ||
); | ||
} | ||
} | ||
|
||
const devDependencyVersion = | ||
consumerPackageManifest.devDependencies?.[updatedPackageName]; | ||
|
||
if (devDependencyVersion && devDependencyVersion !== '*') { | ||
const updatedDependencyVersion = devDependencyVersion.startsWith('^') | ||
? `^${updatedPackageVersion}` | ||
: updatedPackageVersion; | ||
|
||
if (updatedDependencyVersion !== devDependencyVersion) { | ||
console.log( | ||
`\uD83D\uDCA1 ${consumerPackageManifest.name} was updated: now using version ${updatedPackageVersion} of ${updatedPackageName}`, | ||
); | ||
|
||
const updatedPackageManifest = { | ||
...consumerPackageManifest, | ||
devDependencies: { | ||
...consumerPackageManifest.devDependencies, | ||
[updatedPackageName]: updatedDependencyVersion, | ||
}, | ||
}; | ||
|
||
writeFileSync( | ||
consumerPackageManifestPath, | ||
JSON.stringify(updatedPackageManifest, null, 2) + '\n', | ||
'utf-8', | ||
); | ||
} | ||
} | ||
}; | ||
|
||
const alignPackageVersions = () => { | ||
if (checkForGitChanges()) { | ||
console.log( | ||
'\u274c Found uncommitted changes. Please commit or stash them before running this script', | ||
); | ||
|
||
process.exit(1); | ||
} | ||
|
||
forEachPackage((packageAbsolutePath, _, packageManifest) => { | ||
checkIfShouldUpdateDependencyPackageVersion( | ||
ROOT_LOCATION, | ||
packageManifest.name, | ||
packageManifest.version, | ||
); | ||
|
||
checkIfShouldUpdateDependencyPackageVersion( | ||
TEMPLATE_LOCATION, | ||
packageManifest.name, | ||
packageManifest.version, | ||
); | ||
|
||
checkIfShouldUpdateDependencyPackageVersion( | ||
REPO_CONFIG_LOCATION, | ||
packageManifest.name, | ||
packageManifest.version, | ||
); | ||
|
||
forEachPackage(pathToPackage => | ||
checkIfShouldUpdateDependencyPackageVersion( | ||
pathToPackage, | ||
packageManifest.name, | ||
packageManifest.version, | ||
), | ||
); | ||
}); | ||
|
||
if (!checkForGitChanges()) { | ||
console.log( | ||
'\u2705 There were no changes. Every consumer package uses the actual version of dependency package.', | ||
); | ||
return; | ||
} | ||
|
||
console.log('Running yarn to update lock file...'); | ||
spawnSync('yarn', ['install'], { | ||
cwd: ROOT_LOCATION, | ||
shell: true, | ||
stdio: 'inherit', | ||
encoding: 'utf-8', | ||
}); | ||
}; | ||
|
||
alignPackageVersions(); |
52 changes: 52 additions & 0 deletions
52
scripts/monorepo/bump-all-updated-packages/bump-package-version.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* 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 | ||
*/ | ||
|
||
const {writeFileSync} = require('fs'); | ||
const path = require('path'); | ||
|
||
const getIncrementedVersion = (version, increment) => | ||
kelset marked this conversation as resolved.
Show resolved
Hide resolved
|
||
version | ||
.split('.') | ||
.map((token, index) => { | ||
const indexOfVersionToIncrement = increment === 'minor' ? 1 : 2; | ||
|
||
if (index === indexOfVersionToIncrement) { | ||
return parseInt(token, 10) + 1; | ||
} | ||
|
||
if (index > indexOfVersionToIncrement) { | ||
return 0; | ||
} | ||
|
||
return token; | ||
}) | ||
.join('.'); | ||
|
||
const bumpPackageVersion = ( | ||
packageAbsolutePath, | ||
packageManifest, | ||
increment = 'patch', | ||
) => { | ||
const updatedVersion = getIncrementedVersion( | ||
packageManifest.version, | ||
increment, | ||
); | ||
|
||
// Not using simple `npm version patch` because it updates dependencies and yarn.lock file | ||
writeFileSync( | ||
path.join(packageAbsolutePath, 'package.json'), | ||
JSON.stringify({...packageManifest, version: updatedVersion}, null, 2) + | ||
'\n', | ||
'utf-8', | ||
); | ||
|
||
return updatedVersion; | ||
}; | ||
|
||
module.exports = bumpPackageVersion; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a super big fan of this double forEach which feels a bit like brute forcing checking everything against everything but honestly hey at least we'll make sure that everything is correctly aligned!
And I think this will work out of the box with -stable branches too so 👍