22// Licensed under the MIT license.
33/**
44 * GitHub Actions publish workflow template
5- * Push-to-main trigger with commit ID choice, environment selection, and multi-env stages
5+ * Push-to-main trigger with commit ID choice and a single parameterized publish
6+ * job driven by a workflow-level environment variable (TARGET_ENV)
67 */
78
89export interface PublishWorkflowConfig {
@@ -11,22 +12,58 @@ export interface PublishWorkflowConfig {
1112}
1213
1314export function generatePublishWorkflow ( config : PublishWorkflowConfig ) : string {
15+ const defaultEnvironment = config . environments [ 0 ] ?? 'dev' ;
1416 const envChoices = config . environments . map ( ( env ) => ` - ${ env } ` ) . join ( '\n' ) ;
1517
16- const envJobs = config . environments . map ( ( env , idx ) => {
17- const envUpper = env . toUpperCase ( ) ;
18- const autoDeployComment = idx === 0
19- ? ` # To enable automatic deployment on push to main, uncomment the condition below:
20- # if: github.event.inputs.ENVIRONMENT == '${ env } ' || github.event_name == 'push'`
21- : ` # To enable automatic deployment on push to main, uncomment the condition below:
22- # if: github.event.inputs.ENVIRONMENT == '${ env } ' || github.event_name == 'push'
23- # And change needs to: needs: [get-commit, publish-${ config . environments [ idx - 1 ] } ]` ;
24-
25- return ` publish-${ env } :
26- ${ autoDeployComment }
27- if: github.event.inputs.ENVIRONMENT == '${ env } '
18+ return `name: Run APIM Publisher
19+
20+ on:
21+ push:
22+ branches:
23+ - main
24+ paths:
25+ - '${ config . artifactDir } /**'
26+ - 'configuration.*.yaml'
27+ workflow_dispatch:
28+ inputs:
29+ COMMIT_ID_CHOICE:
30+ description: 'Choose "publish-all-artifacts-in-repo" only when you want to force republishing all artifacts (e.g. after build failure). Otherwise stick with the default behavior of "publish-artifacts-in-last-commit"'
31+ required: true
32+ type: choice
33+ default: publish-artifacts-in-last-commit
34+ options:
35+ - publish-artifacts-in-last-commit
36+ - publish-all-artifacts-in-repo
37+ ENVIRONMENT:
38+ description: 'Choose which environment to publish to'
39+ required: true
40+ type: choice
41+ default: ${ defaultEnvironment }
42+ options:
43+ ${ envChoices }
44+
45+ permissions:
46+ id-token: write
47+ contents: read
48+
49+ # A single workflow-level variable selects the target environment. On manual runs
50+ # it comes from the ENVIRONMENT input; on push to main it defaults to '${ defaultEnvironment } '.
51+ env:
52+ TARGET_ENV: \${{ github.event.inputs.ENVIRONMENT || '${ defaultEnvironment } ' }}
53+
54+ jobs:
55+ get-commit:
2856 runs-on: ubuntu-latest
29- environment: ${ env }
57+ outputs:
58+ commit_id: \${{ steps.commit.outputs.commit_id }}
59+ steps:
60+ - name: Set the Commit Id
61+ id: commit
62+ run: echo "commit_id=\${GITHUB_SHA}" >> $GITHUB_OUTPUT
63+
64+ publish:
65+ runs-on: ubuntu-latest
66+ environment: \${{ github.event.inputs.ENVIRONMENT || '${ defaultEnvironment } ' }}
3067 needs: get-commit
3168 steps:
3269 - name: Checkout repository
@@ -42,22 +79,29 @@ ${autoDeployComment}
4279 - name: Install dependencies
4380 run: npm install
4481
82+ - name: Resolve target environment
83+ id: env
84+ run: |
85+ echo "name=\${TARGET_ENV}" >> "$GITHUB_OUTPUT"
86+ echo "upper=\$(echo "\${TARGET_ENV}" | tr '[:lower:]' '[:upper:]')" >> "$GITHUB_OUTPUT"
87+
4588 - name: Azure Login (Federated Credential)
4689 uses: azure/login@v2
4790 with:
4891 client-id: \${{ secrets.AZURE_CLIENT_ID }}
4992 tenant-id: \${{ secrets.AZURE_TENANT_ID }}
5093 subscription-id: \${{ secrets.AZURE_SUBSCRIPTION_ID }}
5194
52- - name: Validate token source values ( ${ env } )
95+ - name: Validate token source values
5396 env:
5497 AVAILABLE_SECRETS_JSON: \${{ toJSON(secrets) }}
5598 run: |
5699 missing=0
57- tokens=$(grep -o '{#\\[[^]]*\\]#}' configuration.${ env } .yaml | sed -E 's/^\\{#\\[([^]]+)\\]#\\}$/\\1/' | sort -u || true)
100+ config_file="configuration.\${TARGET_ENV}.yaml"
101+ tokens=$(grep -o '{#\\[[^]]*\\]#}' "$config_file" | sed -E 's/^\\{#\\[([^]]+)\\]#\\}$/\\1/' | sort -u || true)
58102
59103 if [ -z "$tokens" ]; then
60- echo "No tokens found in configuration. ${ env } .yaml "
104+ echo "No tokens found in $config_file "
61105 exit 0
62106 fi
63107
@@ -86,111 +130,67 @@ ${autoDeployComment}
86130 exit 1
87131 fi
88132
89- - name: Substitute tokens in configuration. ${ env } .yaml
133+ - name: Substitute tokens in configuration file
90134 uses: cschleiden/replace-tokens@v1.3
91135 with:
92136 tokenPrefix: '{#['
93137 tokenSuffix: ']#}'
94- files: '["configuration.${ env } .yaml"]'
138+ files: '["configuration.\${{ env.TARGET_ENV } }.yaml"]'
95139 # Token values are injected in the previous step based on token names.
96- # Ensure tokens in configuration. ${ env } .yaml match secret names exactly.
140+ # Ensure tokens in the configuration file match secret names exactly.
97141
98- - name: Validate token substitution ( ${ env } )
142+ - name: Validate token substitution
99143 run: |
100- if grep -q '{#\\[' configuration.${ env } .yaml; then
101- echo "Unresolved tokens remain in configuration.${ env } .yaml"
102- grep -o '{#\\[[^]]*\\]#}' configuration.${ env } .yaml | sort -u
144+ config_file="configuration.\${TARGET_ENV}.yaml"
145+ if grep -q '{#\\[' "$config_file"; then
146+ echo "Unresolved tokens remain in $config_file"
147+ grep -o '{#\\[[^]]*\\]#}' "$config_file" | sort -u
103148 exit 1
104149 fi
105150
106- - name: Dry-run validation (${ env } , incremental)
151+ - name: Dry-run validation (incremental)
107152 if: \${{ github.event.inputs.COMMIT_ID_CHOICE != 'publish-all-artifacts-in-repo' }}
108153 run: |
109154 npx apiops publish \\
110155 --subscription-id \${{ secrets.AZURE_SUBSCRIPTION_ID }} \\
111- --resource-group \${{ secrets. APIM_RESOURCE_GROUP_${ envUpper } }} \\
112- --service-name \${{ secrets. APIM_SERVICE_NAME_${ envUpper } }} \\
156+ --resource-group \${{ secrets[format(' APIM_RESOURCE_GROUP_{0}', steps.env.outputs.upper)] }} \\
157+ --service-name \${{ secrets[format(' APIM_SERVICE_NAME_{0}', steps.env.outputs.upper)] }} \\
113158 --source ${ config . artifactDir } \\
114- --overrides configuration.${ env } .yaml \\
159+ --overrides configuration.\${{ env.TARGET_ENV } }.yaml \\
115160 --commit-id \${{ needs.get-commit.outputs.commit_id }} \\
116161 --dry-run
117162
118- - name: Dry-run validation (${ env } , all artifacts)
163+ - name: Dry-run validation (all artifacts)
119164 if: \${{ github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' }}
120165 run: |
121166 npx apiops publish \\
122167 --subscription-id \${{ secrets.AZURE_SUBSCRIPTION_ID }} \\
123- --resource-group \${{ secrets. APIM_RESOURCE_GROUP_${ envUpper } }} \\
124- --service-name \${{ secrets. APIM_SERVICE_NAME_${ envUpper } }} \\
168+ --resource-group \${{ secrets[format(' APIM_RESOURCE_GROUP_{0}', steps.env.outputs.upper)] }} \\
169+ --service-name \${{ secrets[format(' APIM_SERVICE_NAME_{0}', steps.env.outputs.upper)] }} \\
125170 --source ${ config . artifactDir } \\
126- --overrides configuration.${ env } .yaml \\
171+ --overrides configuration.\${{ env.TARGET_ENV } }.yaml \\
127172 --dry-run
128173
129- - name: Publish to ${ env } (incremental - last commit only)
174+ - name: Publish (incremental - last commit only)
130175 if: \${{ github.event.inputs.COMMIT_ID_CHOICE != 'publish-all-artifacts-in-repo' }}
131176 run: |
132177 npx apiops publish \\
133178 --subscription-id \${{ secrets.AZURE_SUBSCRIPTION_ID }} \\
134- --resource-group \${{ secrets. APIM_RESOURCE_GROUP_${ envUpper } }} \\
135- --service-name \${{ secrets. APIM_SERVICE_NAME_${ envUpper } }} \\
179+ --resource-group \${{ secrets[format(' APIM_RESOURCE_GROUP_{0}', steps.env.outputs.upper)] }} \\
180+ --service-name \${{ secrets[format(' APIM_SERVICE_NAME_{0}', steps.env.outputs.upper)] }} \\
136181 --source ${ config . artifactDir } \\
137- --overrides configuration.${ env } .yaml \\
182+ --overrides configuration.\${{ env.TARGET_ENV } }.yaml \\
138183 --commit-id \${{ needs.get-commit.outputs.commit_id }}
139184
140- - name: Publish to ${ env } (all artifacts)
185+ - name: Publish (all artifacts)
141186 if: \${{ github.event.inputs.COMMIT_ID_CHOICE == 'publish-all-artifacts-in-repo' }}
142187 run: |
143188 npx apiops publish \\
144189 --subscription-id \${{ secrets.AZURE_SUBSCRIPTION_ID }} \\
145- --resource-group \${{ secrets. APIM_RESOURCE_GROUP_${ envUpper } }} \\
146- --service-name \${{ secrets. APIM_SERVICE_NAME_${ envUpper } }} \\
190+ --resource-group \${{ secrets[format(' APIM_RESOURCE_GROUP_{0}', steps.env.outputs.upper)] }} \\
191+ --service-name \${{ secrets[format(' APIM_SERVICE_NAME_{0}', steps.env.outputs.upper)] }} \\
147192 --source ${ config . artifactDir } \\
148- --overrides configuration.${ env } .yaml
149- ` ;
150- } ) . join ( '\n' ) ;
151-
152- return `name: Run APIM Publisher
153-
154- on:
155- push:
156- branches:
157- - main
158- paths:
159- - '${ config . artifactDir } /**'
160- - 'configuration.*.yaml'
161- workflow_dispatch:
162- inputs:
163- COMMIT_ID_CHOICE:
164- description: 'Choose "publish-all-artifacts-in-repo" only when you want to force republishing all artifacts (e.g. after build failure). Otherwise stick with the default behavior of "publish-artifacts-in-last-commit"'
165- required: true
166- type: choice
167- default: publish-artifacts-in-last-commit
168- options:
169- - publish-artifacts-in-last-commit
170- - publish-all-artifacts-in-repo
171- ENVIRONMENT:
172- description: 'Choose which environment to publish to'
173- required: true
174- type: choice
175- default: ${ config . environments [ 0 ] }
176- options:
177- ${ envChoices }
178-
179- permissions:
180- id-token: write
181- contents: read
182-
183- jobs:
184- get-commit:
185- runs-on: ubuntu-latest
186- outputs:
187- commit_id: \${{ steps.commit.outputs.commit_id }}
188- steps:
189- - name: Set the Commit Id
190- id: commit
191- run: echo "commit_id=\${GITHUB_SHA}" >> $GITHUB_OUTPUT
192-
193- ${ envJobs }
193+ --overrides configuration.\${{ env.TARGET_ENV }}.yaml
194194` ;
195195}
196196
0 commit comments