@@ -9,165 +9,202 @@ const {cd, cp, exec: _exec, set} = require('shelljs');
99set ( '-e' ) ;
1010
1111
12- // Arguments, environment variables and constants.
13- const args = process . argv . slice ( 2 ) ;
14- const dryRun = args [ 0 ] === '--dry-run' ;
15-
16- const {
17- CI_AIO_MIN_PWA_SCORE ,
18- CI_BRANCH ,
19- CI_COMMIT ,
20- CI_PULL_REQUEST ,
21- CI_REPO_NAME ,
22- CI_REPO_OWNER ,
23- CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN ,
24- CI_STABLE_BRANCH ,
25- } = process . env ;
26-
12+ // Constants
2713const REPO_SLUG = 'angular/angular' ;
2814const NG_REMOTE_URL = `https://github.com/${ REPO_SLUG } .git` ;
2915
30- // Do not deploy if we are running in a fork.
31- if ( `${ CI_REPO_OWNER } /${ CI_REPO_NAME } ` !== REPO_SLUG ) {
32- console . log ( `Skipping deploy because this is not ${ REPO_SLUG } .` ) ;
33- process . exit ( 0 ) ;
34- }
16+ // Exports
17+ module . exports = {
18+ computeDeploymentInfo,
19+ computeInputVars,
20+ getLatestCommit,
21+ } ;
3522
36- // Do not deploy if this is a PR. PRs are deployed in the `aio_preview` CircleCI job.
37- if ( CI_PULL_REQUEST !== 'false' ) {
38- console . log ( 'Skipping deploy because this is a PR build.' ) ;
39- process . exit ( 0 ) ;
40- }
23+ // Run
24+ if ( require . main === module ) {
25+ const isDryRun = process . argv [ 2 ] === '--dry-run' ;
26+ const inputVars = computeInputVars ( process . env ) ;
27+ const deploymentInfo = computeDeploymentInfo ( inputVars ) ;
4128
42- // Do not deploy if the current commit is not the latest on its branch.
43- const latestCommit = exec ( `git ls-remote ${ NG_REMOTE_URL } ${ CI_BRANCH } ` ) . slice ( 0 , 40 ) ;
44- if ( CI_COMMIT !== latestCommit ) {
45- console . log ( `Skipping deploy because ${ CI_COMMIT } is not the latest commit (${ latestCommit } ).` ) ;
46- process . exit ( 0 ) ;
29+ if ( deploymentInfo . skipped ) {
30+ console . log ( deploymentInfo . reason ) ;
31+ } else {
32+ console . log (
33+ `Git branch : ${ currentBranch } \n` +
34+ `Build/deploy mode : ${ deploymentInfo . deployEnv } \n` +
35+ `Firebase project : ${ deploymentInfo . projectId } \n` +
36+ `Firebase site : ${ deploymentInfo . siteId } \n` +
37+ `Deployment URLs : ${ deploymentInfo . deployedUrl } \n` ) ;
38+
39+ if ( ! isDryRun ) {
40+ deploy ( { ...inputVars , ...deploymentInfo } ) ;
41+ }
42+ }
4743}
4844
49- // The deployment mode is computed based on the branch we are building.
50- const currentBranchMajorVersion = computeMajorVersion ( CI_BRANCH ) ;
51- // Special-case v9, because it is piloting the Firebase hosting "multisites" setup.
52- // See https://angular-team.atlassian.net/browse/DEV-125 for more info.
53- const isV9 = currentBranchMajorVersion === 9 ;
54- const deployInfoPerTarget = {
55- next : {
56- deployEnv : 'next' ,
57- projectId : 'aio-staging' ,
58- siteId : 'aio-staging' ,
59- deployedUrl : 'https://next.angular.io/' ,
60- } ,
61- rc : {
62- deployEnv : 'rc' ,
63- projectId : 'angular-io' ,
64- siteId : 'rc-angular-io-site' ,
65- deployedUrl : 'https://rc.angular.io/' ,
66- } ,
67- stable : {
68- deployEnv : 'stable' ,
69- projectId : 'angular-io' ,
70- siteId : 'angular-io' ,
71- deployedUrl : 'https://angular.io/' ,
72- } ,
73- archive : {
74- deployEnv : 'archive' ,
75- projectId : isV9 ? 'aio-staging' : `v${ currentBranchMajorVersion } -angular-io` ,
76- siteId : isV9 ? 'v9-angular-io' : `v${ currentBranchMajorVersion } -angular-io` ,
77- deployedUrl : `https://v${ currentBranchMajorVersion } .angular.io/` ,
78- } ,
79- } ;
80- let deployInfo = null ;
81-
82- if ( CI_BRANCH === 'master' ) {
83- deployInfo = deployInfoPerTarget . next ;
84- } else if ( CI_BRANCH === CI_STABLE_BRANCH ) {
85- deployInfo = deployInfoPerTarget . stable ;
86- } else {
87- const stableBranchMajorVersion = computeMajorVersion ( CI_STABLE_BRANCH ) ;
88-
89- // Find the branch that has highest minor version for the given `currentBranchMajorVersion`.
90- const mostRecentMinorVersionBranch =
91- // List the branches that start with the major version.
92- exec ( `git ls-remote ${ NG_REMOTE_URL } refs/heads/${ currentBranchMajorVersion } .*.x` ) . split ( '\n' )
93- // Extract the version number.
94- . map ( line => line . split ( '/' ) [ 2 ] )
95- // Sort by the minor version.
96- . sort ( ( a , b ) => a . split ( '.' ) [ 1 ] - b . split ( '.' ) [ 1 ] )
97- // Get the highest version.
98- . pop ( ) ;
99-
100- // Do not deploy if it is not the latest branch for the given major version.
101- // NOTE: At this point, we know the current branch is not the stable branch.
102- if ( CI_BRANCH !== mostRecentMinorVersionBranch ) {
103- console . log (
104- `Skipping deploy of branch "${ CI_BRANCH } " to Firebase.\n` +
105- 'There is a more recent branch with the same major version: ' +
106- `"${ mostRecentMinorVersionBranch } "` ) ;
107- process . exit ( 0 ) ;
45+ // Helpers
46+ function computeDeploymentInfo (
47+ { currentBranch, currentCommit, isPullRequest, repoName, repoOwner, stableBranch} ) {
48+ // Do not deploy if we are running in a fork.
49+ if ( `${ repoOwner } /${ repoName } ` !== REPO_SLUG ) {
50+ return skipDeployment ( `Skipping deploy because this is not ${ REPO_SLUG } .` ) ;
10851 }
10952
110- deployInfo = ( currentBranchMajorVersion < stableBranchMajorVersion ) ?
111- // This is the latest minor version for a major that is less than the stable major version:
112- // Deploy as `archive`.
113- deployInfoPerTarget . archive :
114- // This is the latest minor version for a major that is equal or greater than the stable major
115- // version, but not the stable version itself:
116- // Deploy as `rc`.
117- deployInfoPerTarget . rc ;
118- }
53+ // Do not deploy if this is a PR. PRs are deployed in the `aio_preview` CircleCI job.
54+ if ( isPullRequest ) {
55+ return skipDeployment ( 'Skipping deploy because this is a PR build.' ) ;
56+ }
11957
120- const { deployEnv, projectId, siteId, deployedUrl} = deployInfo ;
121- console . log (
122- `Git branch : ${ CI_BRANCH } \n` +
123- `Build/deploy mode : ${ deployEnv } \n` +
124- `Firebase project : ${ projectId } \n` +
125- `Firebase site : ${ siteId } \n` +
126- `Deployment URL : ${ deployedUrl } \n` ) ;
58+ // Do not deploy if the current commit is not the latest on its branch.
59+ const latestCommit = getLatestCommit ( currentBranch ) ;
60+ if ( currentCommit !== latestCommit ) {
61+ return skipDeployment (
62+ `Skipping deploy because ${ currentCommit } is not the latest commit (${ latestCommit } ).` ) ;
63+ }
12764
128- if ( dryRun ) {
129- process . exit ( 0 ) ;
130- }
65+ // The deployment mode is computed based on the branch we are building.
66+ const currentBranchMajorVersion = computeMajorVersion ( currentBranch ) ;
67+ // Special-case v9, because it is piloting the Firebase hosting "multisites" setup.
68+ // See https://angular-team.atlassian.net/browse/DEV-125 for more info.
69+ const isV9 = currentBranchMajorVersion === 9 ;
70+ const deploymentInfoPerTarget = {
71+ next : {
72+ deployEnv : 'next' ,
73+ projectId : 'aio-staging' ,
74+ siteId : 'aio-staging' ,
75+ deployedUrl : 'https://next.angular.io/' ,
76+ } ,
77+ rc : {
78+ deployEnv : 'rc' ,
79+ projectId : 'angular-io' ,
80+ siteId : 'rc-angular-io-site' ,
81+ deployedUrl : 'https://rc.angular.io/' ,
82+ } ,
83+ stable : {
84+ deployEnv : 'stable' ,
85+ projectId : 'angular-io' ,
86+ siteId : 'angular-io' ,
87+ deployedUrl : 'https://angular.io/' ,
88+ } ,
89+ archive : {
90+ deployEnv : 'archive' ,
91+ projectId : isV9 ? 'aio-staging' : `v${ currentBranchMajorVersion } -angular-io` ,
92+ siteId : isV9 ? 'v9-angular-io' : `v${ currentBranchMajorVersion } -angular-io` ,
93+ deployedUrl : `https://v${ currentBranchMajorVersion } .angular.io/` ,
94+ } ,
95+ } ;
96+
97+ if ( currentBranch === 'master' ) {
98+ return deploymentInfoPerTarget . next ;
99+ } else if ( currentBranch === stableBranch ) {
100+ return deploymentInfoPerTarget . stable ;
101+ } else {
102+ const stableBranchMajorVersion = computeMajorVersion ( stableBranch ) ;
103+
104+ // Find the branch that has highest minor version for the given `currentBranchMajorVersion`.
105+ const mostRecentMinorVersionBranch =
106+ // List the branches that start with the major version.
107+ getRemoteRefs ( `refs/heads/${ currentBranchMajorVersion } .*.x` )
108+ // Extract the version number.
109+ . map ( line => line . split ( '/' ) [ 2 ] )
110+ // Sort by the minor version.
111+ . sort ( ( a , b ) => a . split ( '.' ) [ 1 ] - b . split ( '.' ) [ 1 ] )
112+ // Get the highest version.
113+ . pop ( ) ;
114+
115+ // Do not deploy if it is not the latest branch for the given major version.
116+ // NOTE: At this point, we know the current branch is not the stable branch.
117+ if ( currentBranch !== mostRecentMinorVersionBranch ) {
118+ return skipDeployment (
119+ `Skipping deploy of branch "${ currentBranch } " to Firebase.\n` +
120+ 'There is a more recent branch with the same major version: ' +
121+ `"${ mostRecentMinorVersionBranch } "` ) ;
122+ }
123+
124+ return ( currentBranchMajorVersion < stableBranchMajorVersion ) ?
125+ // This is the latest minor version for a major that is less than the stable major version:
126+ // Deploy as `archive`.
127+ deploymentInfoPerTarget . archive :
128+ // This is the latest minor version for a major that is equal or greater than the stable
129+ // major version, but not the stable version itself:
130+ // Deploy as `rc`.
131+ deploymentInfoPerTarget . rc ;
132+ }
131133
132- // Deploy
133- cd ( `${ __dirname } /..` ) ;
134+ // We should never get here.
135+ throw new Error ( 'Failed to determine deployment info.' ) ;
136+ }
134137
135- console . log ( '\n\n\n==== Build the AIO app. ====\n' ) ;
136- yarn ( `build --configuration=${ deployEnv } --progress=false` ) ;
138+ function computeInputVars ( {
139+ CI_AIO_MIN_PWA_SCORE : minPwaScore ,
140+ CI_BRANCH : currentBranch ,
141+ CI_COMMIT : currentCommit ,
142+ CI_PULL_REQUEST ,
143+ CI_REPO_NAME : repoName ,
144+ CI_REPO_OWNER : repoOwner ,
145+ CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN : firebaseToken ,
146+ CI_STABLE_BRANCH : stableBranch ,
147+ } ) {
148+ return {
149+ currentBranch,
150+ currentCommit,
151+ firebaseToken,
152+ isPullRequest : CI_PULL_REQUEST !== 'false' ,
153+ minPwaScore,
154+ repoName,
155+ repoOwner,
156+ stableBranch,
157+ } ;
158+ }
137159
138- console . log ( '\n\n\n==== Add any mode-specific files into the AIO distribution. ====\n' ) ;
139- cp ( '-rf' , `src/extra-files/${ deployEnv } /.` , 'dist/' ) ;
160+ function computeMajorVersion ( branchName ) {
161+ return + branchName . split ( '.' , 1 ) [ 0 ] ;
162+ }
140163
164+ function deploy (
165+ { currentCommit, deployedUrl, deployEnv, firebaseToken, minPwaScore, projectId, siteId} ) {
166+ cd ( `${ __dirname } /..` ) ;
141167
142- console . log ( '\n\n\n==== Update opensearch descriptor for AIO with `deployedUrl` . ====\n' ) ;
143- yarn ( `set-opensearch-url ${ deployedUrl . replace ( / [ ^ / ] $ / , '$&/' ) } ` ) ; // The URL must end with `/`.
168+ console . log ( '\n\n\n==== Build the AIO app . ====\n' ) ;
169+ yarn ( `build --configuration= ${ deployEnv } --progress=false ` ) ;
144170
145- console . log ( '\n\n\n==== Check payload size and upload the numbers to Firebase DB . ====\n' ) ;
146- yarn ( 'payload-size ') ;
171+ console . log ( '\n\n\n==== Add any mode-specific files into the AIO distribution . ====\n' ) ;
172+ cp ( '-rf' , `src/extra-files/ ${ deployEnv } /.` , 'dist/ ') ;
147173
148- console . log ( '\n\n\n==== Deploy AIO to Firebase hosting. ====\n' ) ;
149- yarn ( `firebase use "${ projectId } " --token "${ CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN } "` ) ;
150- yarn (
151- `firebase target:apply hosting aio "${ siteId } " --token ` +
152- `"${ CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN } "` ) ;
153- yarn (
154- `firebase deploy --only hosting:aio --message "Commit: ${ CI_COMMIT } " --non-interactive ` +
155- `--token ${ CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN } ` ) ;
174+ console . log ( '\n\n\n==== Update opensearch descriptor for AIO with `deployedUrl`. ====\n' ) ;
175+ yarn ( `set-opensearch-url ${ deployedUrl . replace ( / [ ^ / ] $ / , '$&/' ) } ` ) ; // The URL must end with `/`.
156176
157- console . log ( '\n\n\n==== Run PWA-score tests . ====\n' ) ;
158- yarn ( `test-pwa-score " ${ deployedUrl } " " ${ CI_AIO_MIN_PWA_SCORE } "` ) ;
177+ console . log ( '\n\n\n==== Check payload size and upload the numbers to Firebase DB . ====\n' ) ;
178+ yarn ( 'payload-size' ) ;
159179
180+ console . log ( '\n\n\n==== Deploy AIO to Firebase hosting. ====\n' ) ;
181+ yarn ( `firebase use "${ projectId } " --token "${ firebaseToken } "` ) ;
182+ yarn ( `firebase target:apply hosting aio "${ siteId } " --token "${ firebaseToken } "` ) ;
183+ yarn (
184+ `firebase deploy --only hosting:aio --message "Commit: ${ currentCommit } " --non-interactive ` +
185+ `--token "${ firebaseToken } "` ) ;
160186
161- // Helpers
162- function computeMajorVersion ( branchName ) {
163- return + branchName . split ( '.' , 1 ) [ 0 ] ;
187+ console . log ( '\n\n\n==== Run PWA-score tests. ====\n' ) ;
188+ yarn ( `test-pwa-score "${ deployedUrl } " "${ minPwaScore } "` ) ;
164189}
165190
166191function exec ( cmd , opts ) {
167192 // Using `silent: true` to ensure no secret env variables are printed.
168193 return _exec ( cmd , { silent : true , ...opts } ) . trim ( ) ;
169194}
170195
196+ function getRemoteRefs ( refOrPattern , remote = NG_REMOTE_URL ) {
197+ return exec ( `git ls-remote ${ remote } ${ refOrPattern } ` ) . split ( '\n' ) ;
198+ }
199+
200+ function getLatestCommit ( branchName , remote = undefined ) {
201+ return getRemoteRefs ( branchName , remote ) [ 0 ] . slice ( 0 , 40 ) ;
202+ }
203+
204+ function skipDeployment ( reason ) {
205+ return { reason, skipped : true } ;
206+ }
207+
171208function yarn ( cmd ) {
172209 // Using `--silent` to ensure no secret env variables are printed.
173210 return exec ( `yarn --silent ${ cmd } ` ) ;
0 commit comments