@@ -2,51 +2,136 @@ import getReleasePlan from '@changesets/get-release-plan';
22import { GitClient } from './components/git_client.js' ;
33import { readPackageJson } from './components/package-json/package_json.js' ;
44import { EOL } from 'os' ;
5+ import { ReleasePlan , VersionType } from '@changesets/types' ;
56
6- const gitClient = new GitClient ( ) ;
7-
8- const baseRef = process . argv [ 2 ] ;
9- if ( baseRef === undefined ) {
10- throw new Error ( 'No base ref specified for changeset completeness check' ) ;
7+ enum VersionTypeEnum {
8+ 'NONE' = 0 ,
9+ 'PATCH' = 1 ,
10+ 'MINOR' = 2 ,
11+ 'MAJOR' = 3 ,
1112}
1213
13- const releasePlan = await getReleasePlan ( process . cwd ( ) ) ;
14+ const checkForMissingChangesets = async (
15+ releasePlan : ReleasePlan ,
16+ gitClient : GitClient ,
17+ baseRef : string
18+ ) => {
19+ const packagesWithChangeset = new Set (
20+ releasePlan . releases . map ( ( release ) => release . name )
21+ ) ;
1422
15- const packagesWithChangeset = new Set (
16- releasePlan . releases . map ( ( release ) => release . name )
17- ) ;
23+ const changedFiles = await gitClient . getChangedFiles ( baseRef ) ;
24+ const modifiedPackageDirs = new Set < string > ( ) ;
1825
19- const changedFiles = await gitClient . getChangedFiles ( baseRef ) ;
26+ changedFiles
27+ . filter (
28+ ( changedFile ) =>
29+ changedFile . startsWith ( 'packages/' ) && ! changedFile . endsWith ( 'test.ts' )
30+ )
31+ . forEach ( ( changedPackageFile ) => {
32+ modifiedPackageDirs . add (
33+ changedPackageFile . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' )
34+ ) ;
35+ } ) ;
2036
21- const modifiedPackageDirs = new Set < string > ( ) ;
37+ const packagesMissingChangesets = [ ] ;
38+ for ( const modifiedPackageDir of modifiedPackageDirs ) {
39+ const { name : modifiedPackageName , private : isPrivate } =
40+ await readPackageJson ( modifiedPackageDir ) ;
41+ if ( isPrivate ) {
42+ continue ;
43+ }
44+ if ( ! packagesWithChangeset . has ( modifiedPackageName ) ) {
45+ packagesMissingChangesets . push ( modifiedPackageName ) ;
46+ }
47+ }
2248
23- changedFiles
24- . filter (
25- ( changedFile ) =>
26- changedFile . startsWith ( 'packages/' ) && ! changedFile . endsWith ( 'test.ts' )
27- )
28- . forEach ( ( changedPackageFile ) => {
29- modifiedPackageDirs . add (
30- changedPackageFile . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' )
49+ if ( packagesMissingChangesets . length > 0 ) {
50+ throw new Error (
51+ `The following packages have changes but are not included in any changeset:${ EOL } ${ EOL } ${ packagesMissingChangesets . join (
52+ EOL
53+ ) } ${ EOL } ${ EOL } Add a changeset using 'npx changeset add'.`
3154 ) ;
32- } ) ;
33-
34- const packagesMissingChangesets = [ ] ;
35- for ( const modifiedPackageDir of modifiedPackageDirs ) {
36- const { name : modifiedPackageName , private : isPrivate } =
37- await readPackageJson ( modifiedPackageDir ) ;
38- if ( isPrivate ) {
39- continue ;
4055 }
41- if ( ! packagesWithChangeset . has ( modifiedPackageName ) ) {
42- packagesMissingChangesets . push ( modifiedPackageName ) ;
56+ } ;
57+
58+ const convertVersionType = ( version : VersionType ) : VersionTypeEnum => {
59+ switch ( version ) {
60+ case 'major' :
61+ return VersionTypeEnum . MAJOR ;
62+ case 'minor' :
63+ return VersionTypeEnum . MINOR ;
64+ case 'patch' :
65+ return VersionTypeEnum . PATCH ;
66+ case 'none' :
67+ return VersionTypeEnum . NONE ;
4368 }
44- }
69+ } ;
4570
46- if ( packagesMissingChangesets . length > 0 ) {
47- throw new Error (
48- `The following packages have changes but are not included in any changeset:${ EOL } ${ EOL } ${ packagesMissingChangesets . join (
49- EOL
50- ) } ${ EOL } ${ EOL } Add a changeset using 'npx changeset add'.`
71+ const findEffectiveVersion = (
72+ releasePlan : ReleasePlan ,
73+ packageName : string
74+ ) : VersionTypeEnum => {
75+ let effectiveVersion : VersionTypeEnum = VersionTypeEnum . NONE ;
76+
77+ for ( const changeset of releasePlan . changesets ) {
78+ for ( const release of changeset . releases ) {
79+ if ( release . name === packageName ) {
80+ const releaseVersionType = convertVersionType ( release . type ) ;
81+ if ( releaseVersionType > effectiveVersion ) {
82+ effectiveVersion = releaseVersionType ;
83+ }
84+ }
85+ }
86+ }
87+ return effectiveVersion ;
88+ } ;
89+
90+ const checkBackendDependenciesVersion = ( releasePlan : ReleasePlan ) => {
91+ const backendVersion : VersionTypeEnum = findEffectiveVersion (
92+ releasePlan ,
93+ '@aws-amplify/backend'
94+ ) ;
95+ const backendAuthVersion : VersionTypeEnum = findEffectiveVersion (
96+ releasePlan ,
97+ '@aws-amplify/backend-auth'
98+ ) ;
99+ const backendDataVersion : VersionTypeEnum = findEffectiveVersion (
100+ releasePlan ,
101+ '@aws-amplify/backend-data'
51102 ) ;
103+ const backendFunctionVersion : VersionTypeEnum = findEffectiveVersion (
104+ releasePlan ,
105+ '@aws-amplify/backend-function'
106+ ) ;
107+ const backendStorageVersion : VersionTypeEnum = findEffectiveVersion (
108+ releasePlan ,
109+ '@aws-amplify/backend-storage'
110+ ) ;
111+
112+ if (
113+ backendVersion <
114+ Math . max (
115+ backendAuthVersion ,
116+ backendDataVersion ,
117+ backendFunctionVersion ,
118+ backendStorageVersion
119+ )
120+ ) {
121+ throw new Error (
122+ `@aws-amplify/backend has a version bump of a different kind from its dependencies (@aws-amplify/backend-auth, @aws-amplify/backend-data, @aws-amplify/backend-function, or @aws-amplify/backend-storage) but is expected to have a version bump of the same kind.${ EOL } `
123+ ) ;
124+ }
125+ } ;
126+
127+ const gitClient = new GitClient ( ) ;
128+
129+ const baseRef = process . argv [ 2 ] ;
130+ if ( baseRef === undefined ) {
131+ throw new Error ( 'No base ref specified for changeset completeness check' ) ;
52132}
133+
134+ const releasePlan = await getReleasePlan ( process . cwd ( ) ) ;
135+
136+ await checkForMissingChangesets ( releasePlan , gitClient , baseRef ) ;
137+ checkBackendDependenciesVersion ( releasePlan ) ;
0 commit comments