Ostatnio pisałam o podstawach Cake. Dzisiaj czas na nowy projekt wykorzystujący Cake do uruchamiania skryptów np. az-cli. Stworzyłam na GitHubie specjalne repozytorium, z którego możecie korzystać.
Jeszcze zanim zaczniemy, upewnijcie się, że macie zainstalowane Azure CLI oraz npm. Dodatkowo polecam też wtyczkę markdownlint do VSCode – przydaje się podczas pisania dokumentacji z użyciem składni markdown.
Struktura
Na początek opiszę strukturę repozytorium.

Starałam się odpowiednio pogrupować pliki dotyczące command-runners i commands (dla naszego przykładu commands-az.cake do uruchamiania skryptów az-cli).
Podstawowy plik, który będziemy uruchamiać, to deploy.ps1. Jest to powershellowy plik uruchamiający Cake. W jego logice jest zawarte pobieranie Cake i innych narzędzi z Nuget i uruchomienie skryptu deploy.cake z przekazaniem odpowiednich parametrów. Taki plik można wziąć z oficjalnego repozytorium Cake – należy tylko uważać na wersje. Aktualna wersja do uruchamiania Cake używa Invoke-Expression (końcówka pliku):
# Start Cake
Write-Host „Running build script…”
Invoke-Expression „& $CAKE_EXE_INVOCATION $($cakeArguments -join ” „)”
exit $LASTEXITCODE
Niestety ta wersja nie działała podczas przekazywania w parametrach zmiennych zawierających znaki specjalne. Żeby to naprawić można używać wcześniejszej wersji skryptu:
# Start Cake
Write-Host „Running build script…”
&$CAKE_EXE $cakeArguments
exit $LASTEXITCODE
Główny plik, w którym będziemy pisać logikę, to deploy.cake. To w nim tworzymy na starcie (w metodzie Setup()) nowe instancje CommandRunner dla az-cli oraz PowershellCommanRunner dla powershella. W tym pliku definiujemy też główne zadania (Task()), które będziemy uruchamiać. Domyślnie będzie zawsze brany Task(„Default-Az-Show-Version”), ale używając odpowiednich parametrów, można zmienić wywoływany task.
Popatrzmy na powershell-command-runner.cake, po którym dziedziczą wszystkie inne pliku runner.
public class PowershellCommandRunner { protected ICakeContext context; protected bool globalExceptionOnError; public PowershellCommandRunner(ICakeContext context, bool globalExceptionOnError = true) { this.context = context; this.globalExceptionOnError = globalExceptionOnError; } //... }
W konstruktorze przekazujemy context, a także ustawiamy globalExceptionOnError (domyślnie na true). W skrócie – jest potrzebna taka „furtka”, żeby pozwolić skryptowi działać dalej pomimo warningu. Niestety az-cli czasami wyświetla warning pomimo sukcesu operacji. W domyślnym ustawieniu nasz skrypt się przerwie z powodu błędu. Dlatego dla konkretnych operacji można ustawić powyższą flagę na false, wtedy „połykamy błąd” i skrypt leci dalej. Oczywiście są również mankamenty takiego rozwiązania – gdy operacja się naprawdę wysypie, nasz skrypt będzie dalej wykonywał kolejne kroki.
Widzimy, że mamy 3 metody:
- Run<T>() pozwala na wywołanie skryptu i zdeserializowanie outputu jako konkretnego obiektu o typie T.
- Run() pozwala wywołać skrypt, bez zwracania outputu.
- RunCommand() zawiera już bezpośrednio logikę związaną z uruchomieniem skryptu Powershell z naszą komendą. W powyższym przykładzie mogłaby być prywatna.
Przypatrzmy się Command-Runner.cake.
public class CommandRunner : PowershellCommandRunner { private string toolName; public CommandRunner(ICakeContext context, string toolName, bool globalExceptionOnError = true) : base(context, globalExceptionOnError) { this.toolName = toolName; } //... }
Dziedziczy on po PowershellCommandRunner. W konstruktorze przyjmuje 3 parametry: context, toolName i globalExceptionOnError ustawiony na true. Najważniejszy parametr to toolName – jest to odpowiednik nazwy narzędzia, którą chcemy wywołać. Dla az-cli jest to po prostu „az” (bo używamy go jako „az login”, gdzie „login” jest już konkretną komendą).
Dodatkowo utworzyłam również npm-command-runner.cake. Pozwala on na uruchamianie skryptów zainstalowanych przez npm.
public class NpmCommandRunner: CommandRunner { public NpmCommandRunner(ICakeContext context, string commandName, bool globalExceptionOnError = false) : base(context, context.MakeAbsolute(new FilePath($"./node_modules/.bin/{commandName}.cmd")).FullPath, globalExceptionOnError) { } }
Potrzebujemy przekazać mu w kontruktorze commandName, który będzie szukał odpowiedniego pliku {commandName}.cmd w folderze node_modules/.bin/.
W folderze commands możemy dodawać pliki command dla różnych narzędzi. W naszym przykładzie mamy tylko jeden plik commands-az.cake. Mamy w nim 3 taski:
Task("Az-Show-Version") .Does(() => { az.Run(a => { a.Append("version"); }); }); Task("Login") .Does(() => { //exceptionOnError: false because of default warning //"WARNING: You have logged in. Now let us find all //the subscriptions to which you have access..." az.Run(a => { a.Append("login"); }, exceptionOnError: false); }); Task("Set-Subscription") .Does(() => { az.Run(a => { a.Append("account"); a.Append("set"); a.AppendSwitchQuoted("--subscription", ReleaseVariable("subscription")); }); });
- „Az-Show-Version” – do wyświetlania wersji az
- „Login” – do logowania się
- „Set-Subscription” – do ustawiania subskrypcji (po zalogowaniu)
Jak widać w ostatnim tasku, potrzebujemy pobrać zmienną subscription korzystając z ReleaseVariable.
ReleaseVariable
W celu definiowania zmiennych korzystam z paczki Cake.Deploy.Variables. Dzięki niej definiuję odrębne pliki ze zmiennymi dla różnych środowisk. W projekcie mamy domyślny plik variables-default.cake:
// example of basic variable file ReleaseEnvironment("default") .AddVariable("subscription", x => Argument<string>("subscription"));
oraz dodatkowy plik dla środowiska dev variables-dev.cake:
// example of new variable file for other environment ReleaseEnvironment("dev") .IsBasedOn("default") .AddVariable("env", "dev");
Uruchamianie
Jak uruchomić skrypty? Wystarczy uruchomiść skrypt powershell
./deploy.ps1
Wywoła on domyślny task Az-Show-Version. Jeśli chcemy wybrać inny task, wystarczy go podać w parametrze:
./deploy.ps1 -Target Az-Login
A jeśli chcemy wywołać task z przekazaniem dodatkowych zmiennych, możemy to zapisać tak:
./deploy.ps1 --env="dev" --subscription= '*****' -Target Az-Login-With-Set-Subscription
PS
Niedługo po napisaniu tego posta dowiedziałam się, że powstało coś takiego jak Cake.AzureCLI (z tego posta). Rozszerzenie do Cake, pozwalające bezpośrednio używać azure-cli w Cake. Ma swoje plusy i minusy, ale jeśli chcecie korzystać tylko z azure-cli i nie przeszkadza Wam uzależnienie od konkretnej jego wersji, to może warto rozważyć 🙂
Post powstał pod patronatem firmy, w której aktualnie pracuję: Objectivity.
Grafikę tytułową zaprojektował niezastąpiony zespół designu!
Podoba Ci się to, co tworzę? Chcesz dostawać informacje o:
– wydarzeniach, które organizuję lub wspieram (np. konferencje, meetupy, webinary)
– inicjatywach, które organizuję lub wspieram (np. GeekWeekWro, DevAdventCalendar)
– moich prelekcjach, kursach i szkoleniach
– wyróżnionych artykułach z mojego bloga
0% SPAMu, 100% informacji! Krótko i na temat.
Ciekawy artykuł 🙂
Pozdrawiam,
Dariusz Gruca
http://www.DariuszGruca.pl
PolubieniePolubione przez 1 osoba
Dziękuję!
PolubieniePolubienie