@@ -70,13 +70,91 @@ export function convertToJobContainer(context: TemplateContext, container: Templ
7070 }
7171}
7272
73+ export function convertToServiceContainer ( context : TemplateContext , container : TemplateToken ) : Container | undefined {
74+ let image : StringToken | undefined ;
75+ let env : MappingToken | undefined ;
76+ let ports : SequenceToken | undefined ;
77+ let volumes : SequenceToken | undefined ;
78+ let options : StringToken | undefined ;
79+ let entrypoint : StringToken | undefined ;
80+ let command : StringToken | undefined ;
81+
82+ // Skip validation for expressions for now to match
83+ // behavior of the other parsers
84+ for ( const [ , token ] of TemplateToken . traverse ( container ) ) {
85+ if ( token . isExpression ) {
86+ return ;
87+ }
88+ }
89+
90+ if ( isString ( container ) ) {
91+ image = container . assertString ( "container item" ) ;
92+ return { image : image } ;
93+ }
94+
95+ const mapping = container . assertMapping ( "container item" ) ;
96+ if ( mapping )
97+ for ( const item of mapping ) {
98+ const key = item . key . assertString ( "container item key" ) ;
99+ const value = item . value ;
100+
101+ switch ( key . value ) {
102+ case "image" :
103+ image = value . assertString ( "container image" ) ;
104+ break ;
105+ case "credentials" :
106+ convertToJobCredentials ( context , value ) ;
107+ break ;
108+ case "env" :
109+ env = value . assertMapping ( "container env" ) ;
110+ for ( const envItem of env ) {
111+ envItem . key . assertString ( "container env value" ) ;
112+ }
113+ break ;
114+ case "ports" :
115+ ports = value . assertSequence ( "container ports" ) ;
116+ for ( const port of ports ) {
117+ port . assertString ( "container port" ) ;
118+ }
119+ break ;
120+ case "volumes" :
121+ volumes = value . assertSequence ( "container volumes" ) ;
122+ for ( const volume of volumes ) {
123+ volume . assertString ( "container volume" ) ;
124+ }
125+ break ;
126+ case "options" :
127+ options = value . assertString ( "container options" ) ;
128+ break ;
129+ case "entrypoint" :
130+ entrypoint = value . assertString ( "container entrypoint" ) ;
131+ break ;
132+ case "command" :
133+ command = value . assertString ( "container command" ) ;
134+ break ;
135+ default :
136+ context . error ( key , `Unexpected container item key: ${ key . value } ` ) ;
137+ }
138+ }
139+
140+ if ( ! image ) {
141+ context . error ( container , "Container image cannot be empty" ) ;
142+ } else {
143+ return { image, env, ports, volumes, options, entrypoint, command} ;
144+ }
145+ }
146+
73147export function convertToJobServices ( context : TemplateContext , services : TemplateToken ) : Container [ ] | undefined {
74148 const serviceList : Container [ ] = [ ] ;
149+ const flags = context . state . featureFlags as import ( "@actions/expressions/features" ) . FeatureFlags | undefined ;
150+ const useServiceContainer = flags ?. isEnabled ( "allowServiceContainerCommand" ) ?? false ;
75151
76152 const mapping = services . assertMapping ( "services" ) ;
77153 for ( const service of mapping ) {
78154 service . key . assertString ( "service key" ) ;
79- const container = convertToJobContainer ( context , service . value ) ;
155+ const container = useServiceContainer
156+ ? convertToServiceContainer ( context , service . value )
157+ : convertToJobContainer ( context , service . value ) ;
80158 if ( container ) {
81159 serviceList . push ( container ) ;
82160 }
0 commit comments