* ssh-Keys anlegen * rechte obere Ecke auf eigenes Icon klicken * Preferences * "SSH Keys" * existierendes Repository hochladen cd existing_repo git remote rename origin old-origin git remote add origin https://gitlab.com/n1843/test1.git git push -u origin --all git push -u origin --tags ====== Entwicklungsablauf ====== * entwickelt wird nicht auf dem Master-Branch * es wird auf Development-Branches gearbeitet * diese werden gepusht git push --set-upstream origin * in dem Moment wird CI/CD ausgeführt * die tauchen dann in Branches auf und dort kann ein Merge-Request angefordert werden * die Merge-Requests tauchen dann in Merge requests auf ====== CI/CD ====== * Sind die Regeln/Tools die bei bestimmten Ereignissen ausgeführt werden sollen * zum Beispiel bei Push um den Code zu verifizieren * oder zu bestimmten Zeiten um ein Release zu bauen ===== Bestandteile ===== * Pipelines -> oberster Container * Stages -> die Stufen die abgearbeitet werden sollen * Stages werden nacheinander ausgeführt -> Code prüfen, kompilieren, ausrollen * beinhalten Jobs * Jobs der gleichen Stage können parallel zueinander ausgeführt werden * Jobs -> definieren was getan werden soll * Jobs werden durch Runner ausgeführt * Runner -> Systeme die die Jobs entgegennehmen * genaugenommen ist es Software auf einem Host der die Aufträge entgegen nimmt * Runner starten zum Beispiel VMs oder Container auf denen dann die Executor laufen * Executor -> Systeme die die Jobs ausführen * genaugenommen ist es wieder ein Softwareclient * der cloned das Repository * holt sich Artefakte * führt dann den eigentlich Job darauf aus ===== gitlab-ci.yaml ===== * liegt im root des Repositories * definiert was nacheinander auszuführen ist (Stages) * können Verify-Prozesse sein * können Build-Prozesse sein * formuliert in yaml variables: GIT_DEPTH: 0 default: image: snom/sina-portal:2 stages: - static_analyses pylint_commit: stage: static_analyses before_script: - echo "Installing pylint" - pip3 install pylint script: - echo "$CI_COMMIT_SHA" - echo "$CI_COMMIT_BEFORE_SHA" - last_ret=0 - pythonfiles=$(git diff --name-only $CI_COMMIT_SHA $CI_COMMIT_BEFORE_SHA | grep -E '*.py$') || last_ret=$? - > if [[ $last_ret -eq 0 ]]; then echo "linting '$pythonfiles'"; pylint --max-line-length=120 --output-format=text --disable=import-error --reports=n --ignore='sphinx_conf.py,common_types_pb2_grpc.py,common_types_pb.py, phone_system_service_pb2_grpc.py,phone_system_service_pb2.py,qa_service_pb2_grpc.py,qa_service_pb2.py, settings_service_pb2_grpc.py,settings_service_pb2.py' $pythonfiles; else echo "Skipped, no python files to lint"; fi rules: - if: $CI_PIPELINE_SOURCE == "push" pylint_merge: stage: static_analyses before_script: - echo "Installing pylint" - pip3 install pylint script: - echo "$CI_COMMIT_SHA" - echo "$CI_COMMIT_BEFORE_SHA" - last_ret=0 - pythonfiles=$(git diff --name-only origin/$CI_DEFAULT_BRANCH... | grep -E '*.py$') || last_ret=$? - > if [[ $last_ret -eq 0 ]]; then echo "linting '$pythonfiles'"; pylint --max-line-length=120 --output-format=text --disable=import-error --reports=n --ignore='sphinx_conf.py,common_types_pb2_grpc.py,common_types_pb.py, phone_system_service_pb2_grpc.py,phone_system_service_pb2.py,qa_service_pb2_grpc.py,qa_service_pb2.py, settings_service_pb2_grpc.py,settings_service_pb2.py' $pythonfiles; else echo "Skipped, no python files to lint"; fi rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" * Variables definiert globale Variablen * GIT_DEPTH definiert wie viele Commits zurück gecloned werden soll * normalerweise werden nur einige Commits zurück gecloned (shallow clone) * spart Plattenplatz und erhöht Geschwindigkeit * das kann nicht ausreichend sein wenn man zum Beispiel nur Dateien prüfen will die zwischen dem aktuellen und dem vorhergehenden Commit angefasst wurdten * default -> Defaults * image: Das Image für den Container der die Jobs ausführen soll (per Default) * in diesem Fall kommt es von der offiziellen Docker-Registry * stages -> die Stages * enthält Liste von Stages * ein Stage ist eine Gruppe von Aufgaben -> Verification, Building usw. * werden nacheinander abgearbeitet * bestehen aus mehreren Jobs * Jobs können parallel verarbeitet werden * pylint_commit -> Job * Jobs können beliebige Namen haben * stage: Besagt von welchem Stage der Job ist * before_script -> Welche Befehle vor der Script-Sektion ausgeführt werden sollen (Vorbereitungen) * Liste * jeder Listeneintrag ist ein Shell-Befehl (die Shell kann geändert werden) * script -> Script was ausgeführt werden soll als Job * Liste * jeder Eintrag ist ein Shell-Befehl * Variablen vorhergehender Befehle stehen in nachfolgenden Befehlen zur Verfügung * wenn ein Befehl fehlschlägt (Return-Code != 0) schlägt der ganze Job fehl * es werden keine weiteren Stages ausgeführt * es werden keine weiteren Befehle ausgeführt * rules -> Bedingungen unter denen der Job überhaupt ausgeführt wird * if -> Definiert eine Bedingung * Die Variable CI_PIPELINE_SOURCE definiert was die Pipeline ausgelöst hat * u.a. relevant wenn Jobs für Merges ausgeführt werden sollen -> das ist normalerweise nicht der Fall, sondern nur bei Commits * "push" -> ein Commit * "merge_request_event" -> ein Merge-Request * pylint_merge -> ein weiterer Job * dieser wird nur für Merge-Requests ausgeführt -> siehe rules-Sektion * ansonsten ist es weitestgehend gleich zur vorhergehenden Job-Sektion ==== Troubleshooting/Howto ==== ^Problem/Howto ^ Beschreibung ^ | git --diff schlägt fehl | gitlab macht eine "shallow copy", das heißt es checkt nicht die gesamte git-History aus, sondern nur die letzten x Commits. \\ Man kann in der globalen Sektion "Variables" die Variable "GIT_DEPTH" auf 0 setzen | |Befehl soll fehlschlagen dürfen \\ ohne das der Job fehlschlägt| Es muss nur vermieden werden das der gesamte Befehl (also ein Listeneintrag) etwas anderes als 0 zurück gibt. \\ \\ pythonfiles=$(git diff --name-only $CI_COMMIT_SHA $CI_COMMIT_BEFORE_SHA | grep -E '*.py$') || last_ret=$? \\ In obigem Beispiel wird ein git --diff gemacht, wenn das nicht mit 0 zurückkommt wird der Teil hinter "%%|%%%%|%%" ausgeführt - der Return-Wert in einer Variablen gespeichert. Da der zweite Befehl (das Speichern in einer Variable) immer erfolgreich ist wird immer 0 zurückgegeben für diesen Befehl. \\ \\ Code 1 || Code 2 \\ * Es wird erst Code 1 ausgeführt (der Teil der fehlschlagen kann) * schlägt der fehl (und nur dann), wird Code2 ausgeführt \\ Vermutlich könnte man für Code2 auch "exit 0" fix einsetzen, wenn man den Return-Code nicht braucht | |Befehl der mehrere Zeilen umfasst|Yaml interpretiert jeden Zeilenumbruch per Default als neues Element (zum Beispiel als neuen Listeneintrag). \\ liste: - > Zeile1 Zeile2 Zeile3 \\ Alle Zeilen werden als eine Zeile betrachtet, die Zeilenumbrüche werden als Leerzeichen interpretiert. \\ * Das ">" leitet einen Block ein (also alles danach soll als eine Zeichenkette interpretiert werden) * Alle Zeilen die Teil des Blocks müssen zum ">" eingerückt sein | |Verifiziere nur Dateien die sich zum vorhergehenden Commit/zum Master-Branch geändert haben|Für statische Analyse macht es in der Regel nur Sinn die Dateien zu prüfen die sich gegenüber dem vorhergehenden Commit oder wenn es sich um einen Merge handelt gegenüber Master geändert haben und nicht alle Dateien. \\ script: - pythonfiles=$(git diff --name-only $CI_COMMIT_SHA $CI_COMMIT_BEFORE_SHA | grep -E '*.py$') || last_ret=$? * ggf. muss in der globalen variables-Sektion "GIT_DEPTH: 0" gesetzt werden -> sonst macht gitlab ggf. eine shallow-Copy und das git diff schlägt fehl * in pythonfiles werden ggf. die Dateien gespeichert die sich geändert haben * der Befehl der die Unterschiede ermittelt git diff --name-only $CI_COMMIT_SHA $CI_COMMIT_BEFORE_SHA * $CI_COMMIT_SHA -> ist eine Variable die die aktuelle Commit-ID enthält * $CI_COMMIT_BEFORE_SHA -> ist eine Variable die die vorhergehende Commit-ID enthält * das grep dient hier nur dazu die Detailliste weiter zu filtern * "%%|%%%%|%% und das dahinter dient nur der Absicherung, da ggf. nicht 0 als Return-Wert zurückkommt, weil keine Dateien gefunden wurden -> wäre es nicht da und es würden keine Dateien gefunden, dann würde der Befehl 1 zurückgeben als Return-Wert und der Job + alle folgenden Stages fehlschlagen \\ \\ Das Gleiche noch mal für die Dateiliste im Vergleich zum Master-Branch (sinnvoll wenn man beim Merge-Request, wo ja ein ganzer Branch gemerged wird): script: - pythonfiles=$(git diff --name-only origin/$CI_DEFAULT_BRANCH... | grep -E '*.py$') || last_ret=$? * eigentlich alles wie in vorhergehendem Beispiel * $CI_DEFAULT_BRANCH -> Variable die den Namen des Default-Branches enthält (aber ohne "origin" -> das muss ggf. fix vorangestellt werden) | |Job nur ausführen wenn es ein merge-Request ist|Per Default laufen Jobs nur bei Commits, nicht vor Merge-Requests. \\ pylint_commit: …some stuff rules: - if: $CI_PIPELINE_SOURCE == "push" pylint_merge: …some stuff rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" * In obigem Beispiel sind 2 Jobs definiert * pylint_commit läuft nur für Commits ("pushs") * pylint_merge läuft nur wenn es sich um einen Merge-Request handelt * rules -> definieren Regeln die definieren wann ein Job ausgeführt wird * if -> definiert eine Regel * "$CI_PIPELINE_SOURCE" -> Variable enthält was die Pipeline angestoßen hat (welches Event) * "push" -> Commit * "merge_request_event" -> Merge Request | |pylint integrieren| - pylint --rcfile=.pylintrc $pythonfiles; * das Kommando wird im Root des Projektes (des git-Projektes) ausgeführt ".pylintrc" ist damit im Root des Repositories * man kann die .pylintrc also einfach ein- und auschecken wie jede andere Datei auch * $pythonfiles ist die Liste von Dateien die gelinted werden sollen | ===== Auto DevOps ===== * funktioniert so lange kein Regel-File im Repository vorhanden ist * erkennt automatisch die Sprache des Projekts * baut den Code automatisch * scannt den Code automatisch entsprechend automatischer Regeln * testet die Anwendung * innerhalb des Repositories * Settings * CI/CD * Auto DevOps * "Default to Auto DevOps pipeline" anklicken ====== Begriffe ====== ^Abkürzung ^Begriff ^Beschreibung ^ |CI|Continous Integration|Jedes Commit wird automatisch (mit Hilfe von Scripten und Tools) gebaut (oder teilweise gebaut) und getestet| |CD|Continous Delivery|Automatisches Ausrollen der Software, allerdings wird es manuell ausgelöst| |CD|Continous Deployment|Es wird automatisch ausgerollt auf Produktivsysteme| ====== Dinge die eingestellt werden sollten ====== * generell die Dinge unter Settings * Settings -> Merge Requests * Approval * wie viele Leute müssen approven damit ein Merge-Request durchgeht * Merge Method * ob ein Merge-Commit erstellt wird oder nicht * Squash commits when merging * ob die History des gemergten Branches als solche erhalten bleibt oder gesquast wird * Merge checks * Ob alle Pipelines erfolgreich durchlaufen worden sein müssen bevor gemerged werden kann -> das wird man in der Regel wollen * Ob alle Diskussionen beantwortet sein müssen bevor gemerged werden kann * Merge suggestions * Für die Merge-Message vorgeschlagene Texte * Settings -> Integrations * darüber kann man externe Plattformen/Dienste einbinden * zum Beispiel Jira als Issue-Tracker * eine Alternative dazu ist Webhooks * Settings -> Repository * Protected branches -> es macht in der Regel den Zugriff auf den Master-Branch zu beschränken/zu deaktivieren, so dass in Feature-Branches gearbeitet wird, die dann gemerged werden * Settings -> CI/CD * Runners -> erlaubt Runners festzulegen (auf externen Maschinen oder innerhalb von gitlab)