1
+ name : Automation Master Workflow
2
+
3
+ # Controls when the workflow will run
4
+ on :
5
+ # Allows you to run this workflow from another workflow
6
+ workflow_call :
7
+ outputs :
8
+ quality_gate :
9
+ description : " Results from Skyline Quality Gate."
10
+ value : ${{ jobs.validate_skyline_quality_gate.outputs.quality }}
11
+ # artifact-id-release:
12
+ artifact-id :
13
+ description : " Artifact ID of uploaded Package if successful."
14
+ value : ${{ jobs.artifact_creation_registration.outputs.artifact-id }}
15
+ # artifact-id-development:
16
+ # description: "Artifact ID of dev uploaded Package if successful."
17
+ inputs :
18
+ referenceName :
19
+ required : true
20
+ type : string
21
+ runNumber :
22
+ required : true
23
+ type : string
24
+ referenceType :
25
+ required : true
26
+ type : string
27
+ repository :
28
+ required : true
29
+ type : string
30
+ owner :
31
+ required : true
32
+ type : string
33
+ sonarCloudProjectName :
34
+ required : true
35
+ type : string
36
+ secrets :
37
+ api-key :
38
+ required : false
39
+ sonarCloudToken :
40
+ required : true
41
+ azureToken :
42
+ required : false
43
+
44
+ # A workflow run is made up of one or more jobs that can run sequentially or in parallel
45
+ jobs :
46
+ validate_skyline_quality_gate :
47
+ name : SDK Skyline Quality Gate
48
+ runs-on : windows-latest
49
+ env :
50
+ detected-unit-tests : none
51
+ outputs :
52
+ quality : ${{ steps.quality-step.outputs.results }}
53
+ steps :
54
+ - uses : actions/checkout@v4
55
+ with :
56
+ fetch-depth : 0
57
+
58
+ - name : Initialize
59
+ run : |
60
+ echo "workspace" ${{ github.workspace }}
61
+ echo "ref name" ${{ inputs.referenceName }}
62
+ echo "run number" ${{ inputs.runNumber }}
63
+ echo "ref type" ${{ inputs.referenceType }}
64
+ echo "repository" ${{ inputs.repository }}
65
+
66
+ - name : Set up JDK 17
67
+ uses : actions/setup-java@v4
68
+ with :
69
+ java-version : 17
70
+ distribution : ' zulu'
71
+
72
+ - name : Find .sln file
73
+ id : findSlnFile
74
+ run : |
75
+ echo solutionFilePath=$(find . -type f -name '*.sln') >> $GITHUB_OUTPUT
76
+ shell : bash
77
+ - name : Detect .csproj files
78
+ id : detectCsprojFiles
79
+ run : |
80
+ $csprojFileCount = Get-ChildItem . -Recurse -File -Filter *.csproj | Measure-Object | Select-Object -ExpandProperty Count
81
+ $result = "false"
82
+ if($csprojFileCount -gt 0){ $result = "true" }
83
+ Write-Output "csproj-file-present=$($result)" >> $Env:GITHUB_OUTPUT
84
+ shell : pwsh
85
+ # TODO: Refactor this in the future to a single stage with a loop that adds all the sources you specify.
86
+ - name : Enable Skyline GitHub NuGet Registry
87
+ if : inputs.owner == 'SkylineCommunications'
88
+ run : |
89
+ $SOURCE_NAME="PrivateGitHubNugets"
90
+ $SOURCE_URL="https://nuget.pkg.github.com/SkylineCommunications/index.json"
91
+
92
+ # Check if the source exists. If it does, update it.
93
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
94
+ Write-Host "Updating existing source $SOURCE_NAME."
95
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
96
+ } else {
97
+ Write-Host "Adding new source $SOURCE_NAME."
98
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
99
+ }
100
+ shell : pwsh
101
+
102
+ - name : Enable Skyline Azure Cloud NuGet Registry
103
+ env :
104
+ AZURE_TOKEN_EXISTS : ${{ secrets.azureToken }}
105
+ if : env.AZURE_TOKEN_EXISTS != null && inputs.owner == 'SkylineCommunications'
106
+ run : |
107
+ $SOURCE_NAME="CloudNuGets"
108
+ $SOURCE_URL="https://pkgs.dev.azure.com/skyline-cloud/Cloud_NuGets/_packaging/CloudNuGet/nuget/v3/index.json"
109
+
110
+ # Check if the source exists. If it does, update it.
111
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
112
+ Write-Host "Updating existing source $SOURCE_NAME."
113
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
114
+ } else {
115
+ Write-Host "Adding new source $SOURCE_NAME."
116
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
117
+ }
118
+
119
+ - name : Enable Skyline Azure Private NuGet Registry
120
+ env :
121
+ AZURE_TOKEN_EXISTS : ${{ secrets.azureToken }}
122
+ if : env.AZURE_TOKEN_EXISTS != null && inputs.owner == 'SkylineCommunications'
123
+ run : |
124
+ $SOURCE_NAME="PrivateAzureNuGets"
125
+ $SOURCE_URL="https://pkgs.dev.azure.com/skyline-cloud/_packaging/skyline-private-nugets/nuget/v3/index.json"
126
+
127
+ # Check if the source exists. If it does, update it.
128
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
129
+ Write-Host "Updating existing source $SOURCE_NAME."
130
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
131
+ } else {
132
+ Write-Host "Adding new source $SOURCE_NAME."
133
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
134
+ }
135
+
136
+ - name : Building
137
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
138
+ run : dotnet build "${{ steps.findSlnFile.outputs.solutionFilePath }}" -p:DefineConstants="DCFv1%3BDBInfo%3BALARM_SQUASHING" --configuration Release -nodeReuse:false
139
+
140
+ - name : Unit Tests
141
+ # when not using MSTest you'll need to install coverlet.collector nuget in your test solutions
142
+ id : unit-tests
143
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
144
+ run : dotnet test "${{ steps.findSlnFile.outputs.solutionFilePath }}" --filter TestCategory!=IntegrationTest --logger "trx;logfilename=unitTestResults.trx" --collect "XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura,opencover
145
+ continue-on-error : true
146
+
147
+ - name : Install SonarCloud scanner
148
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
149
+ run : |
150
+ dotnet tool install dotnet-sonarscanner --global
151
+
152
+ - name : Prepare SonarCloud Variables
153
+ id : prepSonarCloudVar
154
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
155
+ run : |
156
+ import os
157
+ env_file = os.getenv('GITHUB_ENV')
158
+ with open(env_file, "a") as myfile:
159
+ myfile.write("lowerCaseOwner=" + str.lower("${{ inputs.owner }}"))
160
+ shell : python
161
+
162
+ - name : Get SonarCloud Status
163
+ id : get-sonarcloud-status
164
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
165
+ run : |
166
+ echo "sonarCloudProjectStatus=$(curl https://${{ secrets.sonarCloudToken }}@sonarcloud.io/api/qualitygates/project_status?projectKey=${{ inputs.sonarCloudProjectName }})" >> $env:GITHUB_OUTPUT
167
+ continue-on-error : true
168
+
169
+ - name : Trigger Initial Analysis
170
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true' && fromJson(steps.get-sonarcloud-status.outputs.sonarCloudProjectStatus).projectStatus.status == 'NONE'
171
+ env :
172
+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
173
+ SONAR_TOKEN : ${{ secrets.sonarCloudToken }}
174
+ run : |
175
+ dotnet sonarscanner begin /k:"${{ inputs.sonarCloudProjectName }}" /o:"${{ env.lowerCaseOwner }}" /d:sonar.token="${{ secrets.sonarCloudToken }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" /d:sonar.cs.vstest.reportsPaths="**/TestResults/**.trx"
176
+ dotnet build "${{ steps.findSlnFile.outputs.solutionFilePath }}" -p:DefineConstants="DCFv1%3BDBInfo%3BALARM_SQUASHING" --configuration Release -nodeReuse:false
177
+ dotnet sonarscanner end /d:sonar.token="${{ secrets.sonarCloudToken }}"
178
+ continue-on-error : true
179
+
180
+ - name : Analyze
181
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
182
+ env :
183
+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
184
+ SONAR_TOKEN : ${{ secrets.sonarCloudToken }}
185
+ run : |
186
+ dotnet sonarscanner begin /k:"${{ inputs.sonarCloudProjectName }}" /o:"${{ env.lowerCaseOwner }}" /d:sonar.token="${{ secrets.sonarCloudToken }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" /d:sonar.cs.vstest.reportsPaths="**/TestResults/**.trx"
187
+ dotnet build "${{ steps.findSlnFile.outputs.solutionFilePath }}" -p:DefineConstants="DCFv1%3BDBInfo%3BALARM_SQUASHING" --configuration Release -nodeReuse:false
188
+ dotnet sonarscanner end /d:sonar.token="${{ secrets.sonarCloudToken }}"
189
+ continue-on-error : true
190
+
191
+ - name : SonarCloud Quality Gate check
192
+ id : sonarcloud-quality-gate-check
193
+ if : steps.detectCsprojFiles.outputs.csproj-file-present == 'true'
194
+ uses : sonarsource/sonarqube-quality-gate-action@master
195
+ with :
196
+ scanMetadataReportFile : .sonarqube/out/.sonar/report-task.txt
197
+ continue-on-error : true
198
+ # Force to fail step after specific time.
199
+ timeout-minutes : 5
200
+ env :
201
+ SONAR_TOKEN : ${{ secrets.sonarCloudToken }}
202
+
203
+ - name : Quality Gate
204
+ id : quality-step
205
+ run : |
206
+ if "${{ steps.detectCsprojFiles.outputs.csproj-file-present }}" == "false":
207
+ print("Quality gate skipped as no .csproj files were detected.")
208
+ exit(0)
209
+ if "${{ steps.unit-tests.outcome }}" == "failure" or "${{ steps.sonarcloud-quality-gate-check.outcome }}" == "failure" or "${{ steps.sonarcloud-quality-gate-check.outputs.quality-gate-status }}" == "FAILED":
210
+ print("Quality gate failed due to:")
211
+ if "${{ steps.unit-tests.outcome }}" == "failure":
212
+ print("- Test failures")
213
+ if "${{ steps.sonarcloud-quality-gate-check.outcome }}" == "failure":
214
+ print("- Could not retrieve SonarCloud quality gate status")
215
+ if "${{ steps.sonarcloud-quality-gate-check.outputs.quality-gate-status }}" == "FAILED":
216
+ print("- Code analysis quality gate failed")
217
+ if "${{ steps.unit-tests.outcome }}" == "failure" or "${{ steps.sonarcloud-quality-gate-check.outcome }}" == "failure" or "${{ steps.sonarcloud-quality-gate-check.outputs.quality-gate-status }}" == "FAILED":
218
+ exit(1)
219
+ shell : python
220
+
221
+ artifact_creation :
222
+ name : Artifact Creation
223
+ runs-on : ubuntu-latest
224
+ steps :
225
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
226
+ - uses : actions/checkout@v4
227
+
228
+ - name : Find .sln file
229
+ id : findSlnFile
230
+ run : |
231
+ echo solutionFilePath=$(find . -type f -name '*.sln') >> $GITHUB_OUTPUT
232
+ shell : bash
233
+
234
+ # TODO: Refactor this in the future to a single stage with a loop that adds all the sources you specify.
235
+ - name : Enable Skyline GitHub NuGet Registry
236
+ if : inputs.owner == 'SkylineCommunications'
237
+ run : |
238
+ $SOURCE_NAME="PrivateGitHubNugets"
239
+ $SOURCE_URL="https://nuget.pkg.github.com/SkylineCommunications/index.json"
240
+
241
+ # Check if the source exists. If it does, update it.
242
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
243
+ Write-Host "Updating existing source $SOURCE_NAME."
244
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
245
+ } else {
246
+ Write-Host "Adding new source $SOURCE_NAME."
247
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
248
+ }
249
+ shell : pwsh
250
+
251
+ - name : Enable Skyline Azure Cloud NuGet Registry
252
+ env :
253
+ AZURE_TOKEN_EXISTS : ${{ secrets.azureToken }}
254
+ if : env.AZURE_TOKEN_EXISTS != null && inputs.owner == 'SkylineCommunications'
255
+ run : |
256
+ $SOURCE_NAME="CloudNuGets"
257
+ $SOURCE_URL="https://pkgs.dev.azure.com/skyline-cloud/Cloud_NuGets/_packaging/CloudNuGet/nuget/v3/index.json"
258
+
259
+ # Check if the source exists. If it does, update it.
260
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
261
+ Write-Host "Updating existing source $SOURCE_NAME."
262
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
263
+ } else {
264
+ Write-Host "Adding new source $SOURCE_NAME."
265
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
266
+ }
267
+ shell : pwsh
268
+
269
+ - name : Enable Skyline Azure Private NuGet Registry
270
+ env :
271
+ AZURE_TOKEN_EXISTS : ${{ secrets.azureToken }}
272
+ if : env.AZURE_TOKEN_EXISTS != null && inputs.owner == 'SkylineCommunications'
273
+ run : |
274
+ $SOURCE_NAME="PrivateAzureNuGets"
275
+ $SOURCE_URL="https://pkgs.dev.azure.com/skyline-cloud/_packaging/skyline-private-nugets/nuget/v3/index.json"
276
+
277
+ # Check if the source exists. If it does, update it.
278
+ if (dotnet nuget list source | Select-String -Pattern $SOURCE_NAME) {
279
+ Write-Host "Updating existing source $SOURCE_NAME."
280
+ dotnet nuget update source $SOURCE_NAME --source $SOURCE_URL --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
281
+ } else {
282
+ Write-Host "Adding new source $SOURCE_NAME."
283
+ dotnet nuget add source $SOURCE_URL --name $SOURCE_NAME --username az --password ${{ secrets.azureToken }} --store-password-in-clear-text
284
+ }
285
+ shell : pwsh
286
+
287
+ - name : NuGet restore solution
288
+ run : dotnet restore "${{ steps.findSlnFile.outputs.solutionFilePath }}"
289
+
290
+ - name : Install .NET Tools
291
+ run : |
292
+ dotnet tool install -g Skyline.DataMiner.CICD.Tools.Packager --version 2.0.*
293
+
294
+ - name : Create package name
295
+ id : packageName
296
+ run : |
297
+ tempName="${{ inputs.repository }}"
298
+ echo name=${tempName//[\"\/\\<>|:*?]/_} >> $GITHUB_OUTPUT
299
+ shell : bash
300
+
301
+ - name : Create dmapp package
302
+ if : inputs.referenceType == 'tag'
303
+ run : dataminer-package-create dmapp "${{ github.workspace }}" --type automation --version ${{ inputs.referenceName }} --output "${{ github.workspace }}" --name "${{ steps.packageName.outputs.name }}"
304
+
305
+ - name : Create dmapp package
306
+ if : inputs.referenceType != 'tag'
307
+ run : dataminer-package-create dmapp "${{ github.workspace }}" --type automation --build-number ${{ inputs.runNumber }} --output "${{ github.workspace }}" --name "${{ steps.packageName.outputs.name }}"
308
+
309
+ - uses : actions/upload-artifact@v4
310
+ with :
311
+ name : DataMiner Installation Package
312
+ path : " ${{ github.workspace }}/${{ steps.packageName.outputs.name }}.dmapp"
313
+
314
+ artifact_creation_registration :
315
+ name : Artifact Registration and Upload
316
+ if : inputs.referenceType == 'tag'
317
+ runs-on : ubuntu-latest
318
+ needs : [validate_skyline_quality_gate,artifact_creation]
319
+ env :
320
+ result-artifact-id : none
321
+ outputs :
322
+ artifact-id : ${{ env.result-artifact-id }}
323
+ steps :
324
+ - uses : actions/checkout@v4
325
+ with :
326
+ fetch-depth : 0
327
+
328
+ - name : Find branch
329
+ id : findBranch
330
+ run : |
331
+ #!/bin/bash
332
+ set -e # Exit immediately if a command exits with a non-zero status.
333
+
334
+ # Capture the branches containing the tag and process them
335
+ branches="$(git branch --contains tags/${{ inputs.referenceName }} -r | grep 'origin/' | grep -vE '.*/.*/' | sed 's#origin/##' | paste -sd ",")"
336
+
337
+ # Append to GitHub Actions output
338
+ echo "branch=${branches}" >> $GITHUB_OUTPUT
339
+ shell : bash
340
+
341
+ - name : Target Branch
342
+ id : showResult
343
+ run : echo "${{ steps.findBranch.outputs.branch }}"
344
+
345
+ - name : Retrieve Installation Package
346
+ id : retrieveInstallationPackage
347
+ uses : actions/download-artifact@v4
348
+ with :
349
+ name : DataMiner Installation Package
350
+ path : _DataMinerInstallationPackage
351
+
352
+ - name : Find Installation package
353
+ id : findInstallationPackage
354
+ run : |
355
+ IFS=$'\n'
356
+ echo dmappPackageName=$(find _DataMinerInstallationPackage -type f -name '*.dmapp') >> $GITHUB_OUTPUT
357
+ unset IFS
358
+ shell : bash
359
+ - name : Install .NET Tools
360
+ run : |
361
+ dotnet tool install -g Skyline.DataMiner.CICD.Tools.CatalogUpload --version 3.0.*
362
+ dotnet tool install -g Skyline.DataMiner.CICD.Tools.GitHubToCatalogYaml --version 1.0.*
363
+
364
+ - name : Upload to Catalog
365
+ id : uploadToCatalog
366
+ run : echo "id=$(dataminer-catalog-upload with-registration --path-to-artifact "${{ steps.findInstallationPackage.outputs.dmappPackageName }}" --artifact-version ${{ inputs.referenceName }} --branch "${{ steps.findBranch.outputs.branch }}" --dm-catalog-token ${{ secrets.api-key }})" >> $GITHUB_OUTPUT
367
+
368
+ - name : (Release) Set artifact Id
369
+ run : echo "result-artifact-id=${{ steps.uploadToCatalog.outputs.id }}" >> $GITHUB_ENV
0 commit comments