@@ -83,6 +83,7 @@ describe('create-release-branch (functional)', () => {
8383 private : true ,
8484 workspaces : [ 'packages/*' ] ,
8585 scripts : { foo : 'bar' } ,
86+ packageManager :
'[email protected] ' , 8687 } ) ;
8788 expect (
8889 await environment . readJsonFileWithinPackage ( 'a' , 'package.json' ) ,
@@ -195,6 +196,7 @@ describe('create-release-branch (functional)', () => {
195196 private : true ,
196197 workspaces : [ 'packages/*' ] ,
197198 scripts : { foo : 'bar' } ,
199+ packageManager :
'[email protected] ' , 198200 } ) ;
199201 expect (
200202 await environment . readJsonFileWithinPackage ( 'a' , 'package.json' ) ,
@@ -640,6 +642,263 @@ describe('create-release-branch (functional)', () => {
640642 ) ;
641643 } ) ;
642644
645+ it ( 'updates the dependency version in package "b" when package "a" version is bumped' , async ( ) => {
646+ await withMonorepoProjectEnvironment (
647+ {
648+ packages : {
649+ $root$ : {
650+ name : '@scope/monorepo' ,
651+ version : '1.0.0' ,
652+ directoryPath : '.' ,
653+ } ,
654+ a : {
655+ name : '@scope/a' ,
656+ version : '1.0.0' ,
657+ directoryPath : 'packages/a' ,
658+ } ,
659+ b : {
660+ name : '@scope/b' ,
661+ version : '2.0.0' ,
662+ directoryPath : 'packages/b' ,
663+ } ,
664+ } ,
665+ workspaces : {
666+ '.' : [ 'packages/*' ] ,
667+ } ,
668+ } ,
669+ async ( environment ) => {
670+ await environment . updateJsonFileWithinPackage ( 'b' , 'package.json' , {
671+ dependencies : {
672+ '@scope/a' : '1.0.0' ,
673+ } ,
674+ } ) ;
675+ const constraintsProContent = `
676+ % All packages must have a name and version defined.
677+ \\+ gen_enforced_field(_, 'name', null).
678+ \\+ gen_enforced_field(_, 'version', null).
679+
680+ % All version ranges used to reference one workspace package in another workspace package's \`dependencies\` or \`devDependencies\` must match the current version of that package.
681+ gen_enforced_dependency(Pkg, DependencyIdent, CorrectDependencyRange, DependencyType) :-
682+ DependencyType \\= 'peerDependencies',
683+ workspace_has_dependency(Pkg, DependencyIdent, _, DependencyType),
684+ workspace_ident(DepPkg, DependencyIdent),
685+ workspace_version(DepPkg, DependencyVersion),
686+ atomic_list_concat(['^', DependencyVersion], CorrectDependencyRange),
687+ Pkg \\= DepPkg. % Ensure we do not add self-dependency
688+
689+ % Entry point to check all constraints.
690+ workspace_package(Pkg) :-
691+ package_json(Pkg, _, _).
692+
693+ enforce_all :-
694+ workspace_package(Pkg),
695+ enforce_has_name(Pkg),
696+ enforce_has_version(Pkg),
697+ (package_json(Pkg, 'dependencies', Deps) -> enforce_dependencies(Pkg, Deps) ; true).
698+
699+ enforce_has_name(Pkg) :-
700+ package_json(Pkg, 'name', _).
701+
702+ enforce_has_version(Pkg) :-
703+ package_json(Pkg, 'version', _).
704+
705+ enforce_dependencies(_, []).
706+ enforce_dependencies(Pkg, [DepPkg-DepVersion | Rest]) :-
707+ workspace_package(DepPkg),
708+ package_json(DepPkg, 'version', DepVersion),
709+ enforce_dependency_version(Pkg, DepPkg),
710+ enforce_dependencies(Pkg, Rest).
711+
712+ enforce_dependency_version(Pkg, DepPkg) :-
713+ package_json(Pkg, 'dependencies', Deps),
714+ package_json(DepPkg, 'version', DepVersion),
715+ member(DepPkg-DepVersion, Deps).
716+
717+ update_dependency_version(Pkg, DepPkg) :-
718+ package_json(Pkg, 'dependencies', Deps),
719+ package_json(DepPkg, 'version', DepVersion),
720+ \\+ member(DepPkg-DepVersion, Deps),
721+ Pkg \\= DepPkg, % Ensure we do not add self-dependency
722+ set_package_json(Pkg, 'dependencies', DepPkg, DepVersion).
723+ ` ;
724+
725+ await environment . writeFile ( 'constraints.pro' , constraintsProContent ) ;
726+ await environment . runTool ( {
727+ releaseSpecification : {
728+ packages : {
729+ a : 'major' ,
730+ b : 'intentionally-skip' ,
731+ } ,
732+ } ,
733+ } ) ;
734+
735+ expect (
736+ await environment . readJsonFileWithinPackage ( 'a' , 'package.json' ) ,
737+ ) . toStrictEqual ( {
738+ name : '@scope/a' ,
739+ version : '2.0.0' ,
740+ } ) ;
741+ expect (
742+ await environment . readJsonFileWithinPackage ( 'b' , 'package.json' ) ,
743+ ) . toStrictEqual ( {
744+ name : '@scope/b' ,
745+ version : '2.0.0' ,
746+ dependencies : { '@scope/a' : '^2.0.0' } ,
747+ } ) ;
748+ } ,
749+ ) ;
750+ } ) ;
751+
752+ it ( 'updates the yarn lock file' , async ( ) => {
753+ await withMonorepoProjectEnvironment (
754+ {
755+ packages : {
756+ $root$ : {
757+ name : '@scope/monorepo' ,
758+ version : '1.0.0' ,
759+ directoryPath : '.' ,
760+ } ,
761+ a : {
762+ name : '@scope/a' ,
763+ version : '1.0.0' ,
764+ directoryPath : 'packages/a' ,
765+ } ,
766+ b : {
767+ name : '@scope/b' ,
768+ version : '2.0.0' ,
769+ directoryPath : 'packages/b' ,
770+ } ,
771+ } ,
772+ workspaces : {
773+ '.' : [ 'packages/*' ] ,
774+ } ,
775+ } ,
776+ async ( environment ) => {
777+ await environment . updateJsonFileWithinPackage ( 'b' , 'package.json' , {
778+ dependencies : {
779+ '@scope/a' : '1.0.0' ,
780+ } ,
781+ } ) ;
782+ const constraintsProContent = `
783+ % All packages must have a name and version defined.
784+ \\+ gen_enforced_field(_, 'name', null).
785+ \\+ gen_enforced_field(_, 'version', null).
786+
787+ % All version ranges used to reference one workspace package in another workspace package's \`dependencies\` or \`devDependencies\` must match the current version of that package.
788+ gen_enforced_dependency(Pkg, DependencyIdent, CorrectDependencyRange, DependencyType) :-
789+ DependencyType \\= 'peerDependencies',
790+ workspace_has_dependency(Pkg, DependencyIdent, _, DependencyType),
791+ workspace_ident(DepPkg, DependencyIdent),
792+ workspace_version(DepPkg, DependencyVersion),
793+ atomic_list_concat(['^', DependencyVersion], CorrectDependencyRange),
794+ Pkg \\= DepPkg. % Ensure we do not add self-dependency
795+
796+ % Entry point to check all constraints.
797+ workspace_package(Pkg) :-
798+ package_json(Pkg, _, _).
799+
800+ enforce_all :-
801+ workspace_package(Pkg),
802+ enforce_has_name(Pkg),
803+ enforce_has_version(Pkg),
804+ (package_json(Pkg, 'dependencies', Deps) -> enforce_dependencies(Pkg, Deps) ; true).
805+
806+ enforce_has_name(Pkg) :-
807+ package_json(Pkg, 'name', _).
808+
809+ enforce_has_version(Pkg) :-
810+ package_json(Pkg, 'version', _).
811+
812+ enforce_dependencies(_, []).
813+ enforce_dependencies(Pkg, [DepPkg-DepVersion | Rest]) :-
814+ workspace_package(DepPkg),
815+ package_json(DepPkg, 'version', DepVersion),
816+ enforce_dependency_version(Pkg, DepPkg),
817+ enforce_dependencies(Pkg, Rest).
818+
819+ enforce_dependency_version(Pkg, DepPkg) :-
820+ package_json(Pkg, 'dependencies', Deps),
821+ package_json(DepPkg, 'version', DepVersion),
822+ member(DepPkg-DepVersion, Deps).
823+
824+ update_dependency_version(Pkg, DepPkg) :-
825+ package_json(Pkg, 'dependencies', Deps),
826+ package_json(DepPkg, 'version', DepVersion),
827+ \\+ member(DepPkg-DepVersion, Deps),
828+ Pkg \\= DepPkg, % Ensure we do not add self-dependency
829+ set_package_json(Pkg, 'dependencies', DepPkg, DepVersion).
830+ ` ;
831+ await environment . writeFile ( 'constraints.pro' , constraintsProContent ) ;
832+ const outdatedLockfile = `
833+ # This file is generated by running "yarn install" inside your project.
834+ # Manual changes might be lost - proceed with caution!
835+
836+ __metadata:
837+ version: 6
838+
839+ "@scope/a@^1.0.0, @scope/a@workspace:packages/a":
840+ version: 0.0.0-use.local
841+ resolution: "@scope/a@workspace:packages/a"
842+ languageName: unknown
843+ linkType: soft
844+
845+ "@scope/b@workspace:packages/b":
846+ version: 0.0.0-use.local
847+ resolution: "@scope/b@workspace:packages/b"
848+ dependencies:
849+ "@scope/a": ^1.0.0
850+ languageName: unknown
851+ linkType: soft
852+
853+ "@scope/monorepo@workspace:.":
854+ version: 0.0.0-use.local
855+ resolution: "@scope/monorepo@workspace:."
856+ languageName: unknown
857+ linkType: soft` ;
858+ await environment . writeFile ( 'yarn.lock' , outdatedLockfile ) ;
859+ await environment . runTool ( {
860+ releaseSpecification : {
861+ packages : {
862+ a : 'major' ,
863+ b : 'intentionally-skip' ,
864+ } ,
865+ } ,
866+ } ) ;
867+
868+ const updatedLockfile = `# This file is generated by running "yarn install" inside your project.
869+ # Manual changes might be lost - proceed with caution!
870+
871+ __metadata:
872+ version: 6
873+
874+ "@scope/a@^2.0.0, @scope/a@workspace:packages/a":
875+ version: 0.0.0-use.local
876+ resolution: "@scope/a@workspace:packages/a"
877+ languageName: unknown
878+ linkType: soft
879+
880+ "@scope/b@workspace:packages/b":
881+ version: 0.0.0-use.local
882+ resolution: "@scope/b@workspace:packages/b"
883+ dependencies:
884+ "@scope/a": ^2.0.0
885+ languageName: unknown
886+ linkType: soft
887+
888+ "@scope/monorepo@workspace:.":
889+ version: 0.0.0-use.local
890+ resolution: "@scope/monorepo@workspace:."
891+ languageName: unknown
892+ linkType: soft
893+ ` ;
894+
895+ expect ( await environment . readFile ( 'yarn.lock' ) ) . toStrictEqual (
896+ updatedLockfile ,
897+ ) ;
898+ } ,
899+ ) ;
900+ } ) ;
901+
643902 it ( 'does not update the versions of any packages that have been tagged with intentionally-skip' , async ( ) => {
644903 await withMonorepoProjectEnvironment (
645904 {
@@ -691,6 +950,7 @@ describe('create-release-branch (functional)', () => {
691950 version : '2.0.0' ,
692951 private : true ,
693952 workspaces : [ 'packages/*' ] ,
953+ packageManager :
'[email protected] ' , 694954 } ) ;
695955 expect (
696956 await environment . readJsonFileWithinPackage ( 'a' , 'package.json' ) ,
0 commit comments