Wer schon mal versucht hat Azure Devops & Jenkins miteinander spielen zu lassen, der ist ggf. auch an stumpfe Grenzen geraten.
Du denkst nun, haha "Was für ein Noob, das geht doch voll easy?!" Nuja, pass mal auf.
Das größte Problem bestand darin, dass unsere Jenkins Projekte SSH Connections für git konfiguriert hatten. Warum ist das ein Problem?
Darauf gehe ich etwas näher ein.
In Azure Dev Ops kann man relativ einfach Service Hooks anlegen, um alles mögliche triggern zu lassen. Es war natürlich naheliegend einfach eine Service-Hook zu nehmen, da es dafür ein Jenkins Template gibt.
Okay also eine Service-Hook angelegt und mal ausprobiert.
Nachfolgend ein Beispiel Request:
https://jenkins.some.stuff/git/notifyCommit?url=https:%2F%2Fdev.azure.com%2Ffoo%2Ffoo%2F_git%2Ffoo-repo&sha1=54c5dff4df7123c430afedbde1f230d692029e2f&branches=master
Sieht doch gar nicht schlecht aus, oder? Doch! Wenn ein Jenkins Projekt Konfiguriert ist eine SSH connection zu benutzen, dann wird mit diesem Request gar nichts getriggert, da das Repo nicht zugeordnet werden kann.
Da ich zu faul war nun alle Jenkinsfiles, Dockerfiles und Co. noch einmal anzupassen habe ich mal eben schnell einen Reverse Proxy in go geschrieben, der so ein Request entgegen nimmt und die https url in eine ssh url umschreibt, die ursprünglichen Header wieder anhängt und das ganze zu Jenkins weiter leitet.
Azure Dev Ops denkt nun, es würde einen Push-Request an Jenkins schicken, als URL ist aber der Reverse Proxy hinterlegt.
Für diesen Service habe ich <100 Zeilen gebraucht, dank des echo-frameworks und resty und einem string replace. Es geht vermutlich in noch weniger Lines of Code.
Wenn ihr euch so was auch baut, müsst ihr bei der Entwicklung darauf achten die Service Hooks immer wieder zu reaktivieren, da diese sich nach 3 maligen Fail in folge selbst deaktivieren. Diese Erkenntnis hat mich sicher eine Stunde gekostet.
Die ganze Magie könnt ihr im folgenden Screenshot bewundern. Tatsächlich extrem einfach sowas mit go zu regeln <3
In diesem Beitrag geht es nicht um Prinzipien und Praktiken von Cleancode, sondern um Hilfsmittel speziell für go, die dabei helfen den idiomatischen Weg einzuhalten.
Cleancode ist auch in go eine wichtige Angelegenheit. Als einstieg in die Thematik empfehle ich, dass du dich mit den Tooling, dass go mitbringt vertraut machst. 2 Tools, die dir dabei helfen deinen Code sauber zu halten sind golint und go vet.
Der linter prüft nicht auf die Korrektheit von Code, sondern viel mehr den CodeStyle.
Den standard linter, welcher die meisten Regeln aus dem Buch "Effective Go" kennt und prüft könnt ihr mithilfe vonfolgenden Befehl installieren.
go get -u golang.org/x/lint/golint
Eine einzelne Datei kann man mit folgendem Befehl prüfen lassen:
golint main.go
Es ist auch möglich eine Liste von Dateien anzugeben:
golint file1.go file2.go
Zusätzlich kann auch ein Pfad inklusive aller Unterordner geprüft werden
golint /pfad/zum/project/...
Das vet tool prüft den Code auf Korrektheit.
Dabei untersucht vet den Go-Code und reported verdächtige Konstrukte, wie Printf calls, deren Argument nicht mit dem format string übereinstimmen. Die algorythmen, die Vet benutzt garantieren nicht, dass alle gefundenen Probleme tatsächlich welche sind, aber dafür findet es Fehler, die nicht vom Compiler gefunden werden. Es ist somit immer nützlich mal darüber zu schauen, da gerade features wie das finden von ungenutztem Code, oder auch das fehlende Prüfen auf einen error sehr nützlich sind.
Um go vet zu starten kann einfach folgender Befehl verwendet werden
go vet /pfad/zum/project/...
Dieser untersucht sämtliche packages.
Um ein spezifisches Package zu untersuchen kann der pfad zum package direkt angegeben werden
go vet /pfad/zum/package
Features von go vet
asmdecl report mismatches between assembly files and Go declarations assign check for useless assignments atomic check for common mistakes using the sync/atomic package bools check for common mistakes involving boolean operators buildtag check that +build tags are well-formed and correctly located cgocall detect some violations of the cgo pointer passing rules composites check for unkeyed composite literals copylocks check for locks erroneously passed by value httpresponse check for mistakes using HTTP responses loopclosure check references to loop variables from within nested functions lostcancel check cancel func returned by context.WithCancel is called nilfunc check for useless comparisons between functions and nil printf check consistency of Printf format strings and arguments shift check for shifts that equal or exceed the width of the integer stdmethods check signature of methods of well-known interfaces structtag check that struct field tags conform to reflect.StructTag.Get tests check for common mistaken usages of tests and examples unmarshal report passing non-pointer or non-interface values to unmarshal unreachable check for unreachable code unsafeptr check for invalid conversions of uintptr to unsafe.Pointer unusedresult check for unused results of calls to some functions
Wem der default linter nicht mächtig genug ist, der kann auf golangci-lint zurück greifen. Dieses mächtige Tool ist komplett konfigurierbar und bietet eine wesentlich größere Anzahl an lintern, sowie die möglichkeit einige Fehler direkt zu beheben.
Zusätzlich ist die Ausgabe der Fehler besser lesbar und enthält mehr Informationen, als beim default linter.
Beispiel Ausgabe:
pkg/onboarding/service.go:267:2: Consider preallocating `financialEligibles` (prealloc)
var financialEligibles []models.Individual
^
cmd/local/main.go:31:1: cyclomatic complexity 12 of func `main` is high (> 10) (gocyclo)
func main() {
^
golangci-lint ist als open source Projekt auf github gehostet.
Zum installieren muss lediglich folgender Befehl ausgeführt werden:
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
Golangci lint kann in alle gängigen Editoren/IDEs integriert werden.
Wir halten nun also den default CodeStyle ein und kümmern uns um die Korrektheit. Nun wollen wir natürlich auch noch die korrekte Formatierung nutzen. Dafür gibt es das gofmt tool
Um direkt alle Dateien zu überprüfen und fixes anzuwenden kann folgender command genutzt werden.
go fmt -n -x pfad/zum/projekt/...
Nützlich kann hierbei auch eine git pre push hook sein.
Ein Beispiel dafür findet ihr hier:
https://github.com/edsrzf/gofmt-git-hook
Jeder der sich um Code Qualität sorgt, hat sich schon einmal Gedanken gemacht, wie er das ganze Analysieren kann um ein Gesamtbild zu bekommen. Nun kann man den ganzen Quellcode durchschauen und sich dabei Notizen machen, oder Tickets erstellen für Stellen im Code, die nicht so geil sind, oder man benutzt ein statisches Codeanalysetool. Ich habe mich für eine statische Code Analyse mit Sonarqube entschieden. Sonarqube gibt es als OnPremise und als Cloud variante.
Was braucht man dafür? Natürlich lasse ich das erst mal in einem Docker Container laufen. Dafür tippt man, vorausgesetzt Docker ist installiert, einfach die folgenden 2 Befehle ein:
1 | docker pull sonarqube |
1 | docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube:latest |
Anschließend wartet man einen kurzen Moment, bis der Container hochgefahren ist. Das hat bei mir so 5-10 Sekunden gedauert. Jetzt könnt ihr die Sonarqube Instanz bereits unter localhost:9090 finden
Ruft im Browser den Link http://localhost:9000 auf.
Loggt euch anschließend mit folgenden Credentials ein:
Username: admin
Password: admin
Anschließend könnt ihr ein neues Projekt erstellen. Vergebt dafür einfach einen Namen, bestätigt und anschließend klickt ihr auf Generate.
Ladet euch nun Sonar Scanner herunter. Entpackt diesen an einen beliebigen Ort und fügt den Pfad zum bin Ordner dem Umgebungspfad hinzu.
Startet nun die analyse im folgenden Beispiel habe ich als projectkey "gocloak" gesetzt, da ich ein Projekt mit dem key "gocloak" angelegt habe. Dies müsst ihr durch euren Key austauschen und anschließend im project-root ausführen. Den Login Wert müsst ihr durch den key austauschen, den ihr zuvor erstellt habt.
1 | sonar-scanner -Dsonar.projectKey=gocloak -Dsonar.sources=. -Dsonar.host.url=http://localhost:9000 -Dsonar.login=8f032266ebed7ca4ec79e22f464b8649455bad77 |
Alternativ könnt ihr als Login auch folgendes verwenden:
1 | sonar-scanner -Dsonar.projectKey=gocloak -Dsonar.sources=. -Dsonar.host.url=http://localhost:9000 -Dsonar.login=admin -Dsonar.password=admin |
Ist der Befehl erfolgreich durchgelaufen könnt ihr euch das Ergebnis auf Sonarqube anschauen.
Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu. Weitere Informationen
Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklären Sie sich damit einverstanden.