In Teil 1 der Serie GitLab CI/CD mit PowerShell haben ich meinen Aufbau und den Installationsvorgang der GitLab Umgebung für kleine PowerShell Projekte aufgezeigt.
Nun steigen wir mit diesem Artikel direkt ein, was ein Projekt für Continuous Integration zusätzlich benötigt und wie die Tests bzw. ein Deployment aussehen können.
GitLab CI/CD mit PowerShell – Einführung
Continuous Integration ist In GitLab 8 voll integriert und bei jedem Projekt standardmäßig aktiviert. Um eine CI Pipline bei jedem Merge oder Push auszulösen muss lediglich ein weiteres File im Root des Projektes angelegt werden.
Zusätzliches File: .gitlab-ci.yml
git add .gitlab-ci.yml git commit -m "Add .gitlab-ci.yml" git push origin master
In diesem File werden alle Schritte für den Runner definiert. Die Schritte sind in Stages aufgeteilt: Build, Test, Deploy
Außerhalb der Scripts in den Stages können in dem YAML File noch Pre- und Post-Scripte sowie Variablen definiert werden.
Die GitLab Doku bietet hier einen sehr guten Einblick in die umfangreichen Möglichkeiten.
GitLab CI/CD mit PowerShell – Tests
Wir schauen uns in dem Folgenden Beispiel als erstes die wohl am häufig genutzte Stage an, Test.
.gitlab-ci.yml Beispiel für Tests
variables: GIT_SSL_NO_VERIFY: "true" before_script: - Import-Module PSScriptAnalyzer - Import-Module Pester stages: - test ps_scriptanalyzer: stage: test script: - $res = (Invoke-ScriptAnalyzer -Path . -Severity Error).count - if ($res -gt 0) { throw "$($res) Analytics failed."} tags: - Windows ps_pester: stage: test script: - cd Tests - $res = Invoke-Pester -OutputFormat NUnitXml -OutputFile TestsResults.xml -PassThru - if ($res.FailedCount -gt 0) { throw "$($res.FailedCount) tests failed."} tags: - Windows
Was haben wir in dem Beispiel definiert:
- Variable: Deaktivierung der SSL Verifizierung wegen eines sporadischen Problems
- Pre-Script: Import der PowerShell Module Pester und PSScriptAnalyzer
- Stages: Nur Test Stage
- Job Name: PS_ScriptAnalyzer
- Script: Ausführung der PSScriptAnalyzer Analysten mit Prüfung auf Error Level Fehler
- Tags: Windows (zur Auswahl des Runners)
- Job Name: PS_Pester
- Script: Ausführung der Pester Tests mit Prüfung der Fehler
- Tags: Windows (zur Auswahl des Runners)
Der erfolgreiche Lauf der Pipeline sieht dann so aus
PSScriptAnalyzer Log
Pester Log
Die beiden Beispiel Tests stellen auch für mich meine Baseline der Qualitätskontrolle in meinen Projekten dar.
- Qualität des Codes mit PSScriptAnalyzer anhand der Regeln Prüfen
- Grundlegende Tests mit Pester festlegen
Durch dieses Vorgehen ist die Prüfung des Projekts auch jederzeit außerhalb von GitLab CI/CD mit PowerShell möglich und muss nicht separat erarbeitet werden.
PSScriptAnalyzer
Was ist PSScriptAnalyzer
PSScriptAnalyzer is a static code checker for Windows PowerShell modules and scripts. PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules. The rules are based on PowerShell best practices identified by PowerShell Team and the community. It generates DiagnosticResults (errors and warnings) to inform users about potential code defects and suggests possible solutions for improvements.
In meine Tests in GitLab ziehe ich nur die Errors in PSScriptAnalyzer zu rate. Dies sind z.B. nicht verwendete Variablen oder die Verwendung von reservierten Parametern in Funktionen.
Alle Regeln mit deren Level können in der Übersicht der PSScriptAnalyzer Regel Dokumentation auf GitHub eingesehen werden.
Installation von PSScriptAnalyzer
PowerShell 5
Mit PowerShell 5 ist der beste Weg die direkte Installation aus der PowerShell Gallery.
Install-Module -Name PSScriptAnalyzer Import-Module -Name PSScriptAnalyzer
PowerShell 4
Der einfachste Weg ist der Umweg über die PowerShell 5.
- Das Modul in PowerShell 5 herunterladen
Save-Module -Name PSScriptAnalyzer -Path C:\Temp\
- Dann den Ordner in „C:\Windows\System32\WindowsPowerShell\v1.0\Modules“ auf dem Server mit PowerShell 4 kopieren
- Modul laden
Import-Module -Name PSScriptAnalyzer
Pester
Was ist Pester
Pester provides a framework for running unit tests to execute and validate PowerShell commands from within PowerShell. Pester consists of a simple set of functions that expose a testing domain-specific language (DSL) for isolating, running, evaluating and reporting the results of PowerShell commands.
Pester tests can execute any command or script that is accessible to a Pester test file. This can include functions, cmdlets, modules and scripts. Pester can be run in ad-hoc style in a console or it can be integrated into the build scripts of a continuous integration (CI) system.
Pester ist nicht erst seit GitLab CI/CD mit PowerShell ein wichtiges Werkzeug für mich. Daher versuche ich die CI Tests innerhalb von GitLab so zu erstellen, dass die Tests auch weiterhin direkt in Pester brauchbar sind.
Für Pester Neulinge ist das GitHub Wiki ein guter Start in das Thema.
Installation von Pester
PowerShell 5
Mit PowerShell 5 ist der beste Weg wieder die direkte Installation aus der PowerShell Gallery.
Install-Module -Name Pester Import-Module -Name Pester
PowerShell 4
Der einfachste Weg ist der Download des GitHub Pester Repositorys.
- Das Repository als Zip herunterladen
- Dann das Zip in „C:\Windows\System32\WindowsPowerShell\v1.0\Modules“ auf dem Server mit PowerShell 4 extrahieren
- Modul laden
Import-Module -Name Pester
Meine Basis Tests mit Pester
$here = Split-Path -Parent $MyInvocation.MyCommand.Path $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.' . "$here\$sut" Describe "Get-VMID" { It "Import Module" { $Error.Clear() Import-Module ../Get-VMID.psm1 $PetserTest = (Get-Module -Name Get-VMID) $PetserTest.Count | Should BeGreaterThan 0 $Error.Count | Should BeLessThan 1 } It "Run Module" { $Error.Clear() $Trash = Add-PSSnapin -PassThru VMware.VimAutomation.Core -ErrorAction SilentlyContinue -WarningAction SilentlyContinue $Trash = Connect-VIServer -Server "myvcenter.lan.local" -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue $PetserTest = (Get-VM -Name TEST* | Get-VMID) $PetserTest.Count | Should BeGreaterThan 0 $Error.Count | Should BeLessThan 1 } }
Was Teste ich an Funktionen immer mindestens mit Pester:
- Fehlerfreier Import der Funktion
- Grundlegende Nutzung der Funktion (Wenn das non-Destructive möglich ist)
GitLab CI/CD mit PowerShell – Deploy
Fügt man dem YAML File noch die Stage Deploy hinzu und definiert diese, werden alle Deploy Job Scripte nach den erfolgreichen Tests ausgeführt.
.gitlab-ci.yml Beispiel mit Deployment
variables: GIT_SSL_NO_VERIFY: "true" before_script: - Import-Module PSScriptAnalyzer - Import-Module Pester stages: - test - deploy ps_scriptanalyzer: stage: test script: - $res = (Invoke-ScriptAnalyzer -Path . -Severity Error).count - if ($res -gt 0) { throw "$($res) Analytics failed."} tags: - Windows ps_pester: stage: test script: - cd Tests - $res = Invoke-Pester -OutputFormat NUnitXml -OutputFile TestsResults.xml -PassThru - if ($res.FailedCount -gt 0) { throw "$($res.FailedCount) tests failed."} tags: - Windows copy_to_webserver: stage: deploy script: - $Error.Clear() - cd $CI_PROJECT_DIR - Copy-Item *.ps1 -Destination \\myServer\Folder - Copy-Item *.xml -Destination \\myServer\Folder - if ($Error -gt 0) { throw "$($Error) Errors occured."} tags: - Windows add_to_zip: stage: deploy script: - $Error.Clear() - cd $CI_PROJECT_DIR - $FilePath = $CI_PROJECT_DIR + '\myFile.ps1' - Add-Type -As System.IO.Compression.FileSystem - $Archive = [System.IO.Compression.ZipFile]::Open('\\myServer\Folder\myZip.zip','Update') - $Entry = $Archive.GetEntry('myZip.ps1') - if ($Entry) {$Entry.Delete()} - $Trash = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($Archive, $FilePath, 'myFile.ps1') - $Archive.Dispose() - if ($Error -gt 0) { throw "$($Error) Errors occured."} tags: - Windows
In den Deploy Jobs habe ich auf eine GitLab Runner Variable zugegriffen: $CI_PROJECT_DIR
Die Variable beinhaltet den Pfad in welches das Repositoy für den Build kopiert wird.
Hallo Markus,
ich bin auf diesen Blog-Post gestoßen und es ist genau das was ich brauche. Vielen Dank!
Mein Ziel ist es in meinem selbst gehosteten Gitlab ein Continuous Deployment inzurichten, wo selbst geschriebene Skripte (und Module) auf lokale Repos meiner Kunden verteilt werden.
Ich bin aber noch sehr neu in dem ganzen Thema (auch was git und Gitlab angeht) und scheitere noch an der einen und/oder anderen Stelle.
Ich habe den Runner zum laufen bekommen und die Tests werden soweit durchgeführt. Jeodch erscheint nicht (wie bei dir) die eigentliche Skript-Payload von Pester und ScriptAnalyser im Log-Window. Bei mir sieht es nur so aus:
——-
Running with gitlab-ci-multi-runner 9.5.0 (413da38)
on xxxxx (xxxx)
Using Shell executor…
Running on xxxxx…
Fetching changes…
HEAD is now at c010e43 Merge remote-tracking branch ‚mighty-gitlab/production‘ into dev_ContinuousDeployment
Checking out c010e434 as dev_ContinuousDeployment…
Skipping Git submodules setup
——
danach kommt nichts mehr. Egal, ob ich Skripte pushe oder nut Textdateien, er führt anscheinend weder die import-Module Befehle aus noch den eigentlichen Payload der Tests.
Was mache ich falsch oder habe ich vergessen?
Hallo Andreas,
es freut mich sehr zu hören, dass ich dir mit meinem Blog Artikel helfen kann.
Hast du das „.gitlab-ci.yml“ in deinem Repo angeegt?
Beste Grüße
Markus