1
1
'use strict' ;
2
2
3
3
let cli = require ( 'heroku-cli-util' ) ;
4
- let co = require ( 'co' ) ;
4
+
5
+ const PROMOTION_ORDER = [ "development" , "staging" , "production" ] ;
6
+ const V3_HEADER = 'application/vnd.heroku+json; version=3' ;
7
+ const PIPELINES_HEADER = V3_HEADER + '.pipelines' ;
5
8
6
9
module . exports = {
7
10
topic : 'pipelines' ,
@@ -10,40 +13,66 @@ module.exports = {
10
13
help : "promote an app's slug down the pipeline" ,
11
14
needsApp : true ,
12
15
needsAuth : true ,
13
- flags : [
14
- { name : 'stage' , char : 's' , description : 'stage of first app in pipeline' , hasValue : true }
15
- ] ,
16
16
run : cli . command ( function * ( context , heroku ) {
17
- var stage ;
17
+ const app = context . app ;
18
18
19
- stage = context . flags . stage ;
20
- let promise = heroku . request ( {
19
+ const coupling = yield cli . action ( `Fetching app info` , heroku . request ( {
21
20
method : 'GET' ,
22
- path : `/apps/${ context . app } /pipeline-couplings` ,
23
- headers : { 'Accept' : 'application/vnd.heroku+json; version=3.pipelines' }
21
+ path : `/apps/${ app } /pipeline-couplings` ,
22
+ headers : { 'Accept' : PIPELINES_HEADER }
23
+ } ) ) ;
24
+
25
+ const allApps = yield cli . action ( `Fetching apps from ${ coupling . pipeline . name } ` ,
26
+ heroku . request ( {
27
+ method : 'GET' ,
28
+ path : `/pipelines/${ coupling . pipeline . id } /apps` ,
29
+ headers : { 'Accept' : PIPELINES_HEADER }
30
+ } ) ) ;
31
+
32
+ const sourceStage = coupling . stage ;
33
+ const targetStage = PROMOTION_ORDER [ PROMOTION_ORDER . indexOf ( sourceStage ) + 1 ] ;
34
+
35
+ if ( targetStage == null || PROMOTION_ORDER . indexOf ( sourceStage ) < 0 ) {
36
+ throw new Error ( `Cannot promote ${ app } from '${ sourceStage } ' stage` ) ;
37
+ }
38
+
39
+ const targetApps = allApps . filter ( function ( app ) {
40
+ return app . coupling . stage === targetStage ;
24
41
} ) ;
25
- let coupling = yield cli . action ( `Fetching app info` , promise ) ;
26
42
27
- promise = heroku . request ( {
28
- method : 'GET' ,
29
- path : `/pipelines/${ coupling . pipeline . id } /apps` ,
30
- headers : { 'Accept' : 'application/vnd.heroku+json; version=3.pipelines' }
31
- } ) ; // heroku.pipelines(pipeline_id).apps;
32
- let apps = yield cli . action ( `Fetching apps from ${ coupling . pipeline . id } ` , promise ) ;
33
-
34
- //let order = ["review", "development", "test", "qa", "staging", "production"];
35
-
36
- let next_apps = [ ] ;
37
- for ( var app in apps ) {
38
- if ( apps . hasOwnProperty ( app ) ) {
39
- if ( apps [ app ] . coupling . stage == stage ) next_apps . push ( app ) ;
40
- }
43
+ if ( targetApps . length < 1 ) {
44
+ throw new Error ( `Cannot promote from ${ app } as there are no downstream apps in $(targetStage) stage` ) ;
41
45
}
42
- cli . debug ( next_apps ) ;
43
- for ( var app in next_apps ) {
44
- if ( keys . hasOwnProperty ( app ) ) {
45
- cli . log ( `Promoting ${ context . app } to ${ app . name } (${ stage } )... done, v2` ) ;
46
- }
46
+
47
+ const releases = yield cli . action ( `Fetching latest release from ${ app } ` ,
48
+ heroku . request ( {
49
+ method : 'GET' ,
50
+ path : `/apps/${ app } /releases` ,
51
+ headers : { 'Accept' : V3_HEADER , 'Range' : 'version ..; order=desc,max=1;' }
52
+ } ) ) ;
53
+ cli . hush ( releases ) ;
54
+
55
+ const sourceRelease = releases [ 0 ] ;
56
+
57
+ if ( sourceRelease == null ) {
58
+ throw new Error ( `Cannot promote from ${ app } as it has no builds yet` ) ;
47
59
}
60
+
61
+ const sourceSlug = sourceRelease . slug . id ;
62
+
63
+ yield targetApps . map ( function ( targetApp ) {
64
+ const promotion = heroku . request ( {
65
+ method : 'POST' ,
66
+ path : `/apps/${ targetApp . id } /releases` ,
67
+ headers : {
68
+ 'Accept' : V3_HEADER ,
69
+ 'Heroku-Deploy-Type' : 'pipeline-promote' ,
70
+ 'Heroku-Deploy-Source' : app
71
+ } ,
72
+ body : { slug : sourceSlug }
73
+ } ) ;
74
+
75
+ return cli . action ( `Promoting to ${ targetApp . name } ` , promotion ) ;
76
+ } ) ;
48
77
} )
49
78
} ;
0 commit comments