Typische situaties bij continue integratie

Heb je de Git-commando's geleerd, maar wil je begrijpen hoe continue integratie (Continuous Integration, CI) in de praktijk werkt? Of wil je misschien je dagelijkse taken optimaliseren? Deze cursus biedt je praktische vaardigheden in continue integratie met behulp van een repository op GitHub. Deze cursus is niet bedoeld als een wizard die je gewoon kunt doorlopen; integendeel, je zult dezelfde acties uitvoeren die mensen daadwerkelijk op hun werk doen, op dezelfde manier als zij dat doen. Ik zal de theorie uitleggen terwijl je de stappen met betrekking tot het onderwerp doorloopt.

Wat gaan we doen?

Tijdens de cursus zullen we geleidelijk een lijst met typische CI-stappen opstellen, wat een uitstekende manier is om deze lijst te onthouden. Met andere woorden, we zullen een lijst maken van acties die ontwikkelaars ondernemen bij het uitvoeren van continue integratie. Ook zullen we een eenvoudige set tests gebruiken om ons CI-proces dichter bij de werkelijkheid te brengen.

Deze GIF toont schematisch de commits in je repository terwijl je vordert in de cursus. Zoals je kunt zien, is er niets ingewikkelds en alleen het noodzakelijke.

Typische situaties bij continue integratie

Je zult door de volgende standaard CI-scenario's gaan:

  • Werken aan een functie;
  • Automatische tests toepassen om de kwaliteit te waarborgen;
  • Een prioriteitsopdracht implementeren;
  • Een mergeconflict oplossen;
  • Een fout in de productieomgeving tegenkomen.

Wat zul je leren?

Je zult in staat zijn om de volgende vragen te beantwoorden:

  • Wat is continue integratie (CI)?
  • Welke soorten automatische tests worden gebruikt bij CI en op basis van welke acties worden ze uitgevoerd?
  • Wat is een pull request en wanneer zijn ze nodig?
  • Wat is testgestuurde ontwikkeling (Test Driven Development, TDD) en hoe verhoudt het zich tot CI?
  • Moet ik mergen of wijzigingen toepassen (rebase)?
  • Moet ik terugdraaien of het in de volgende versie oplossen?

In het begin vertaalde ik overal termen zoals "pull request", maar uiteindelijk besloot ik sommige zinnen in het Engels terug te brengen om de gekte in de tekst te verlagen. Soms zal ik 'programmeertaal' gebruiken zoals het bijzondere werkwoord "commit" daar waar mensen dat daadwerkelijk op het werk gebruiken.

Wat is continue integratie?

Continue integratie, of CI, is a technical practice in which each team member integrates their code into a shared repository at least once a day, with the resulting code needing to compile without errors.

There are different interpretations of this term.

The subject of contention is the frequency of integration. Some argue that merging code only once a day is insufficient; true integration should be continuous. An example is a team where everyone pulls fresh code in the morning and integrates once in the evening. Although this is a reasonable argument, it is generally considered that the definition of 'once a day' is practical, specific, and suitable for teams of various sizes.

Another objection is that C++ is no longer the only language used in development, and the requirement of compiling without errors as a means of validation is rather weak. A certain set of tests (for example, unit tests, run locally) should also succeed. Currently, the community tends towards making such requirements mandatory, and in the future, 'build + unit tests' will evidently become the norm if it hasn't already.

Continue integratie is different from continuous delivery (Continuous Delivery, CD) in that it does not require a release candidate after each integration cycle.

The list of steps we will use throughout the course.

  1. Pull in the latest code. Create a branch from master. Start working.
  2. Create commits on your new branch. Build and test locally. Passed? Go to the next step. Failed? Fix errors or tests and try again.
  3. Push to your remote repository or remote branch.
  4. Create a pull request. Discuss the changes, add more commits as the discussion continues. Make tests pass on the feature branch.
  5. Merge/rebase commits from master. Make tests pass on the merge result.
  6. Deploy from the feature branch to production.
  7. If everything is good in production for a certain period, merge changes to master.

Typische situaties bij continue integratie

️ Preparation

Ensure the necessary software is available.

To take this course, you will need Node.js en a Git client..

You can use any Git client, but I will only provide commands for the command line.

Make sure you have a Git client that supports the command line.

If you do not have a command line-supported Git client installed yet, you can find installation instructions. hier.

Prepare the repository.

You will need to create a personal copy (fork) of the template repository with the course code on GitHub. Let's agree to call this personal copy the course repository..

Heb je het gedaan? Als je de standaardinstellingen niet hebt gewijzigd, heet je cursusrepository waarschijnlijk continuous-integration-team-scenarios-students, deze bevindt zich in je account op GitHub en de URL ziet eruit als

https://github.com//continuous-integration-team-scenarios-students

Ik zal dit adres gewoon noemen <URL рСпозитория>.

Hoekige haken zoals <Ρ‚ΡƒΡ‚> geven aan dat je zo'n uitdrukking moet vervangen door de overeenkomstige waarde.

Zorg ervoor dat GitHub-acties zijn ingeschakeld voor deze cursusrepository. Als ze niet zijn ingeschakeld, schakel ze dan in door op de grote knop in het midden van de pagina te klikken, die je kunt bereiken door op Acties in de GitHub-interface te klikken.

Je kunt de cursus niet volgen volgens mijn instructies als GitHub-acties niet zijn ingeschakeld.

Typische situaties bij continue integratie

Je kunt altijd de mogelijkheid van GitHub gebruiken om Markdown weer te geven om de huidige status van de lijst die we hier samenstellen te zien

https://github.com//continuous-integration-team-scenarios-students/blob/master/ci.md

Wat betreft de antwoorden

Hoewel de beste manier om deze cursus te voltooien, is door alles zelf te doen, kunnen er wel eens complicaties optreden.

Als je het gevoel hebt dat je niet begrijpt wat je moet doen en niet verder kunt, kun je de branch solution, die in je startrepository zit, bekijken.
Voer alsjeblieft geen samenvoegingen uit solution in master tijdens de cursus. Je kunt deze branch gebruiken om te begrijpen wat je moet doen, of om je code te vergelijken met die van de auteur, gebruikmakend van alle mogelijkheden die Git ons biedt. Als je volledig vastloopt, kun je je branch volledig vervangen master door de branch solution en vervolgens je werkdirectory resetten naar de cursusstap die je nodig hebt.

Gebruik dit alleen als je het echt nodig hebt.

Commit je code

git add .
git commit -m "Mijn werk veiligstellen"

Deze commando's

  • hernoemen master in master-backup;
  • hernoemen solution in master;
  • schakelen (checkout) naar de nieuwe branch master en herschrijven de inhoud van de werkdirectory;
  • maken een branch 'solution' vanuit 'master' (die eerder 'solution' was) voor het geval je in de toekomst een branch 'solution' nodig hebt.

git branch -m master master-backup
git branch -m solution master
git checkout master -f
git branch solution

Na deze stappen kun je git log master gebruiken om te achterhalen welke commit je nodig hebt.
Je kunt je werkdirectory naar deze commit resetten als volgt:

git reset --hard

Als je tevreden bent met het resultaat, zul je op een gegeven moment je repository versie naar een externe repository (remote) moeten publiceren. Vergeet niet om expliciet de externe branch op te geven wanneer je dit doet.

git push --force origin master

Houd er rekening mee dat we gebruiken git push --force. Het is onwaarschijnlijk dat je dit vaak wilt doen, maar we hebben hier een zeer specifieke situatie met één gebruiker van de repository, die bovendien begrijpt wat hij doet.

Aan de slag

Typische situaties bij continue integratie

Laten we onze lijst van CI-stappen opstellen. Gewoonlijk begin je deze stap met het ophalen van de laatste versie van de code uit de externe repository, maar we hebben nog geen lokale repository, dus in plaats daarvan klonen we deze uit de externe.

️ Taak: werk de lokale repository bij, maak een branch van master, begin met werken

  1. Kloon de cursusrepository van <URL рСпозитория>.
  2. Start npm install in de cursusrepository; dit hebben we nodig voor het installeren van Jest, dat we gebruiken voor het uitvoeren van tests.
  3. Maak een branch en noem deze feature. Schakel over naar deze branch.
  4. Voeg testcode toe in ci.test.js tussen de opmerkingen met het verzoek om dit te doen.

    it('1. haal de laatste code op', () => {
      expect(/.*pull.* /ig.test(fileContents)).toBe(true);
    });
    
    it('2. voeg commits toe', () => {
      expect(/.*commit.* /ig.test(fileContents)).toBe(true);
    });
    
    it('3. push naar de externe branch met dezelfde naam', () => {
      expect(/.*push.* /ig.test(fileContents)).toBe(true);
    });
    
    it('4. maak een pull request en ga door met werken', () => {
      expect(/.*pulls+request.* /ig.test(fileContents)).toBe(true);
    });

  5. Voeg tekst met de eerste 4 stappen toe aan het bestand ci.md.
    1. Haal de laatste code binnen. Maak een branch van `master`. Begin met werken.    
    2. Maak commits op je nieuwe branch. Bouw en test lokaal.  
    Gaat het goed? Ga naar de volgende stap. Fout? Los fouten of tests op en probeer het opnieuw.  
    3. Push naar je externe repository of externe branch.  
    4. Maak een pull request. Bespreek de wijzigingen, voeg meer commits toe  
    aardat de discussie doorgaat. Laat de tests slagen op de feature branch.  

    Teams

# ΠšΠ»ΠΎΠ½ΠΈΡ€ΡƒΠΉΡ‚Π΅ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ курса
git clone <repository URL>
cd <repository name>

# Π’Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ npm install Π² ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ рСпозитория курса; ΠΎΠ½ установит Jest, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ для запуска тСстов.
npm install

# Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ ΠΈ Π½Π°Π·ΠΎΠ²ΠΈΡ‚Π΅ Π΅Π΅ feature. ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ Π½Π° эту Π² Π²Π΅Ρ‚ΠΊΡƒ.
git checkout -b feature

# ΠžΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ci.test.js ΠΊΠ°ΠΊ описано Π²Ρ‹ΡˆΠ΅.
# ΠžΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ci.md ΠΊΠ°ΠΊ описано Π²Ρ‹ΡˆΠ΅

Maak commits op de nieuwe branch, bouw en test lokaal

We gaan de tests instellen zodat ze voor de commit worden uitgevoerd, en vervolgens de code committen.

Typische scenario's waarbij tests automatisch worden uitgevoerd

  • Lokaal:
    • Constant of als reactie op relevante wijzigingen in de code;
    • Bij het opslaan (voor geΓ―nterpreteerde of JIT-gecompileerde talen);
    • Bij het bouwen (wanneer compilatie vereist is);
    • Bij het committen;
    • Bij het publiceren naar een gezamenlijke repository.

  • Op de buildserver of in de buildomgeving:
    • Wanneer de code in een persoonlijke branch/repository wordt gepubliceerd.
    • De code wordt in deze branch getest.
    • De potentiΓ«le samensmeltingsresultaten worden getest (meestal met master).
    • Als een fase van continue integratie/continue levering

Over het algemeen geldt: hoe sneller een set tests wordt uitgevoerd, hoe vaker je deze kunt draaien. Een typische faseverdeling kan er als volgt uitzien.

  • Snelle unit tests - bij het bouwen, in de CI-pipeline
  • Langzame unit tests, snelle component- en integratietests - bij commit, in de CI-pipeline
  • Langzame component- en integratietests - in de CI-pipeline
  • Beveiligingstests, belastingstests en andere langdurige of kostbare tests - in CI/CD-pipelines, maar alleen in specifieke modi/fasen/assembly-pipelines, bijvoorbeeld bij het voorbereiden van een releasekandidaat of bij handmatige uitvoering.

️ Taak

Ik stel voor om eerst de tests handmatig uit te voeren met het commando npm test. Laten we daarna een git hook toevoegen om onze tests bij commit uit te voeren. Er is één snag: Git hooks worden niet beschouwd als onderdeel van de repository en kunnen daarom niet samen met de andere cursusmaterialen van GitHub worden gekloond. Om de hook in te stellen, moet je install_hook.sh of het bestand kopiëren repo/hooks/pre-commit naar de lokale directory .git/hooks/.
Bij het committen zie je dat de tests worden uitgevoerd en dat ze controleren of bepaalde sleutelwoorden aanwezig zijn in de lijst.

  1. Voer de tests handmatig uit met het commando npm test in de repository-map van je cursus. Zorg ervoor dat de tests zijn uitgevoerd.
  2. Stel de hook in voor commit (pre-commit hook) door install_hook.sh.
  3. De wijzigingen naar de lokale repository committen.
  4. Zorg ervoor dat de tests worden uitgevoerd voordat je commit.

Je repository zou er zo uit moeten zien na het uitvoeren van deze acties.
Typische situaties bij continue integratie

Teams

# УстановитС pre-commit hook Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠ² install_hook.sh.  

# Π—Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΡŒΡ‚Π΅ измСнСния Π² Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ "Add first CI steps" Π² качСствС сообщСния ΠΏΡ€ΠΈ ΠΊΠΎΠΌΠΌΠΈΡ‚Π΅.
git add ci.md ci.test.js
git commit -m "Add first CI steps"

# Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ тСсты Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ ΠΏΠ΅Ρ€Π΅Π΄ ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΎΠΌ.  

Publiceer de code naar de externe repository of externe branch

Nadat ze lokaal hebben gewerkt, maken ontwikkelaars doorgaans hun code openbaar, zodat deze uiteindelijk kan worden geΓ―ntegreerd met de gezamenlijke. Met GitHub wordt dit meestal bereikt door werk te publiceren in een persoonlijke kopie van de repository (personal fork) of in een persoonlijke branch.

  • Bij het gebruik van forks kloont de ontwikkelaar een externe gedeelde repository, waardoor hij zijn persoonlijke externe kopie maakt, ook wel een fork genoemd. Vervolgens kloont hij deze persoonlijke repository om lokaal mee te werken. Wanneer het werk klaar is en commits zijn gemaakt, plaatst hij deze in zijn fork, waar ze toegankelijk zijn voor anderen en geΓ―ntegreerd kunnen worden in de gezamenlijke repository. Deze aanpak wordt meestal gebruikt in open source-projecten op GitHub. Het wordt ook gebruikt in mijn uitgebreide cursus [Team Work and CI with Git]http://devops.redpill.solutions/).
  • Een andere aanpak is om slechts één externe repository te gebruiken en alleen de branch master van de gedeelde repository β€˜beschermd’ te beschouwen. In dit scenario publiceren afzonderlijke ontwikkelaars hun code in de branches van de externe repository, zodat anderen deze code kunnen bekijken, en als alles in orde is, kunnen ze deze samenvoegen met master de gezamenlijke repository.

In deze specifieke cursus zullen we een workflow gebruiken die gebruik maakt van branches.

Laten we onze code publiceren.

️ Taak

  • Publiceer de wijzigingen naar een externe branch met dezelfde naam als je werkschema

Teams

git push --set-upstream origin feature

CreΓ«er een pull request

CreΓ«er een pull request met de titel Stappenreview. Stel in feature als 'head branch' en master als 'base branch'.

Zorg ervoor dat je master in je fork van de repository als 'base branch' hebt ingesteld, ik zal geen wijzigingen in de repository met cursusmaterialen accepteren.

In de GitHub-jargon is 'base branch' de branch waarop je jouw werk baseert, en 'head branch' de branch die de voorgestelde wijzigingen bevat.

Bespreek de wijzigingen, voeg nieuwe commits toe terwijl de discussie voortduurt

Pull request (PR)

Pull request (PR) is een manier om code te bespreken en te documenteren, en een code review uit te voeren. Pull requests zijn genoemd naar de gebruikelijke manier om afzonderlijke wijzigingen in de gedeelde code te integreren. Gewoonlijk kloont iemand de externe officiΓ«le repository van het project en werkt lokaal aan de code. Daarna plaatst hij de code in zijn persoonlijke externe repository en vraagt hij de verantwoordelijken van de officiΓ«le repository ompull) zijn code in hun lokale repositories te halen, waar ze deze bekijken en mogelijk integreren,merge) dit te doen. Dit begrip is ook bekend onder andere namen, zoals merge request.

Eigenlijk hoeft u de functie pull request op GitHub of vergelijkbare platforms niet per se te gebruiken. Ontwikkelteams kunnen andere manieren van communicatie gebruiken, waaronder persoonlijke gesprekken, telefoongesprekken of e-mail, maar er zijn toch verschillende redenen om dergelijke pull requests in de stijl van een forumdiscussie te gebruiken. Hier zijn enkele daarvan:

  • georganiseerde discussies met betrekking tot specifieke wijzigingen in de code;
  • als een plek voor het inzien van feedback op onafgebroken werk, zowel van automatische tests als van collega's;
  • formalisatie van codecontroles;
  • om later de redenen en overwegingen achter een bepaald codefragment te kunnen achterhalen.

U maakt meestal een pull request aan wanneer u iets wilt bespreken of feedback wilt ontvangen. Bijvoorbeeld, als u werkt aan een functie die op meerdere manieren kan worden geΓ―mplementeerd, kunt u een wijzigingsverzoek aanmaken voordat u de eerste regel code schrijft, om uw ideeΓ«n te delen en uw plannen met co-auteurs te bespreken. Als het werk eenvoudiger is, wordt de pull request geopend wanneer er al iets is gedaan, vastgelegd en besproken kan worden. In sommige scenario's kunt u een PR alleen openen vanuit een kwaliteitscontroleperspectief: om automatische tests uit te voeren of een codecontrole te initiΓ«ren. Wat u ook besluit, vergeet niet om @ mensen te vermelden wiens goedkeuring nodig is in uw pull request.

Normaal gesproken doet u het volgende bij het aanmaken van een PR.

  • Geef aan wat u wilt wijzigen en waar.
  • Schrijf een beschrijving die het doel van de wijzigingen uitlegt. U kunt bijvoorbeeld willen:
    • iets belangrijks toevoegen dat niet vanzelfsprekend is uit de code, of iets nuttigs voor het begrijpen van de context, zoals relevante #bugs en commitnummers;
    • @noemen wie dan ook met wie u wilt gaan samenwerken, of u kunt ze later in de opmerkingen @noemen;
    • collega's vragen om hulp met iets of iets specifieks te controleren.

Nadat u de PR heeft geopend, worden de tests uitgevoerd die zijn ingesteld om bij dit soort gevallen te draaien. In ons geval is dit dezelfde set tests die we lokaal hebben uitgevoerd, maar in een echt project kunnen er extra tests en controles zijn.

Gelieve te wachten tot de tests zijn voltooid. U kunt de status van de tests onderaan de PR-discussie in de GitHub-interface zien. Ga verder wanneer de tests zijn voltooid.

Voeg een opmerking toe over de willekeurigheid van de CI-stappenlijst

De lijst die in deze cursus wordt gebruikt, is willekeurig en subjectief; we moeten hier een opmerking over toevoegen.

Opdracht: maak een pull request voor deze opmerking

  1. auth0 master.
  2. Maak een branch met de naam bugfix.
  3. Voeg de opmerkingstekst aan het einde van het bestand toe ci.md.
    > **GitHub-flow** wordt soms als bijnaam gebruikt om te verwijzen naar een variant van trunk-gebaseerde ontwikkeling  
    wanneer code rechtstreeks vanuit feature branches wordt gedeployed. Deze lijst is gewoon een interpretatie  
    die ik gebruik in mijn [DevOps-cursussen](http://redpill.solutions).  
    De officiΓ«le tutorial is [hier](https://guides.github.com/introduction/flow/).
  4. Commit de wijzigingen.
  5. Publiceer de branch bugfix naar de externe repository.
  6. Maak een pull request met de naam Een opmerking toevoegen met de hoofdbranch bugfix en de basisbranchmaster.

Zorg ervoor dat je master in je fork van de repository als 'base branch' hebt ingesteld, ik zal geen wijzigingen in de repository met cursusmaterialen accepteren.

Dit is hoe uw repository eruit zou moeten zien.
Typische situaties bij continue integratie

Teams

# ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ Π½Π° Π²Π΅Ρ‚ΠΊΡƒ master. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ bugfix.
git checkout master

# Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ bugfix-remark.
git checkout -b bugfix

# Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ тСкст примСчания Π²Π½ΠΈΠ·Ρƒ ci.md.

# Π—Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΡŒΡ‚Π΅ измСнСния
git add ci.md
git commit -m "Add a remark about the list being opinionated"

# ΠžΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ bugfix Π² ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.
git push --set-upstream origin bugfix

# Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ pull request ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ интСрфСйса GitHub ΠΊΠ°ΠΊ описано Π²Ρ‹ΡˆΠ΅

Bevestig de pull request "Een opmerking toevoegen"

️ Taak

  1. Maak een pull request.
  2. Klik op "Merge pull request".
  3. Klik op "Bevestig de samenvoeging".
  4. Klik op "Verwijder branch", we hebben deze niet meer nodig.

Dit is het commit-diagram na de samenvoeging.
Typische situaties bij continue integratie

Ga door met werken en voeg tests toe.

Samenwerken aan een pull request leidt vaak tot de noodzaak van extra werk. Dit is meestal het resultaat van code review of discussie, maar in onze cursus gaan we dit simuleren door nieuwe items aan onze lijst met CI-stappen toe te voegen.

Bij continue integratie wordt doorgaans enige testdekking toegepast. De vereisten voor testdekking variëren en zijn meestal te vinden in een document genaamd "bijdrageregelgeving" (contribution guidelines). We zullen het eenvoudig houden en één test per regel in onze checklist toevoegen.

Wanneer u opdrachten uitvoert, probeer dan eerst de tests te committen. Als u de pre-commit hook eerder correct heeft ingesteld, wordt de zojuist toegevoegde test uitgevoerd; deze zal niet slagen en er zal niets worden gecommitteerd. Let op: zo leren we dat onze tests daadwerkelijk iets controleren. Interessant genoeg zou, als we met de code vΓ³Γ³r de tests zouden beginnen, het slagen van de tests kunnen betekenen dat ofwel de code werkt zoals verwacht of dat de tests eigenlijk niets controleren. Bovendien, als we in eerste instantie geen tests hadden geschreven, zouden we ze helemaal kunnen vergeten, omdat er niets zou zijn dat ons eraan herinnerde.

Testgestuurd ontwikkelen (TDD)

TDD raadt aan om tests vΓ³Γ³r de code te schrijven. Het gebruikelijke proces bij TDD ziet er als volgt uit.

  1. Voeg een test toe.
  2. Voer alle tests uit en zorg ervoor dat de nieuwe test niet succesvol is.
  3. Schrijf de code.
  4. Voer de tests uit en zorg ervoor dat alle tests succesvol zijn.
  5. Refactor de code.
  6. Herhaal.

Aangezien de resultaten van tests die niet succesvol zijn meestal in het rood worden weergegeven en de succesvolle in het groen, wordt de cyclus ook wel 'rood-groen-refactor' genoemd.

️ Taak

Probeer eerst de tests in te voegen en laat ze falen, voeg dan de tekst van de CI-stappen toe en commit. Je zult zien dat de tests slagen ('groen').
Publiceer vervolgens de nieuwe code in de externe repository en kijk hoe de tests worden uitgevoerd in de interface van GitHub onderaan de pull request-discussie, en hoe de status van de PR wordt bijgewerkt.

  1. auth0 feature.
  2. Voeg deze tests toe aan ci.test.js na de laatste aanroep it (...);.

    it('5. Merge/rebase commits van master. Laat de tests slagen op het resultaat van de merge.', () => {
      expect(/.*merge.*commits.*tests+pass.*/ig.test(fileContents)).toBe(true);
    });
    
    it('6. Deploy vanaf de feature branch naar productie.', () => {
      expect(/.*Deploy.*to+production.*/ig.test(fileContents)).toBe(true);
    });
    
    it('7. Als alles goed is in productie gedurende een bepaalde periode, merge de wijzigingen naar master.', () => {
      expect(/.*merge.*to+master.*/ig.test(fileContents)).toBe(true);
    });

  3. Probeer de tests te committen. Als pre-commit de hook is ingesteld, zal de commit poging falen.
  4. Voeg daarna deze tekst toe aan ci.md.
    5. Merge/rebase commits van master. Laat de tests slagen op het resultaat van de merge.  
    6. Deploy vanaf de feature branch met een heimelijk bug naar productie.
    7. Als alles goed is in productie gedurende een bepaalde periode, merge de wijzigingen naar master. 
  5. Voer en commit wijzigingen lokaal.
  6. Publiceer de wijzigingen naar de branch feature.

Nu zou je iets als dit moeten hebben
Typische situaties bij continue integratie

Teams


# ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Π° Π²Π΅Ρ‚ΠΊΡƒ feature
git checkout feature

# Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ тСсты Π² ci.test.js ΠΊΠ°ΠΊ описано Π²Ρ‹ΡˆΠ΅

# Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π² индСкс ci.test.js Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ·ΠΆΠ΅ Π·Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΈΡ‚ΡŒ
git add ci.test.js

# ΠŸΠΎΠΏΡ‹Ρ‚Π°ΠΉΡ‚Π΅ΡΡŒ Π·Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΈΡ‚ΡŒ тСсты. Если pre-commit hook установлСны, ΠΊΠΎΠΌΠΌΠΈΡ‚ Π½Π΅ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Ρ‘Ρ‚.
git commit

# Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ тСкст Π² ci.md ΠΊΠ°ΠΊ описано Π²Ρ‹ΡˆΠ΅

# ВнСситС измСнСния ΠΈ Π·Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΡŒΡ‚Π΅ ΠΈΡ…
git add ci.md
git commit -m "Add the remaining CI steps"

# ΠžΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠΉΡ‚Π΅ измСнСния Π² Π²Π΅Ρ‚ΠΊΡƒ feature
git push

Merge-conflict

Ga naar de pull request Stappenreview.

Ondanks dat we niets verkeerd hebben gedaan en de tests voor onze code succesvol waren, kunnen we de branch nog steeds niet samenvoegen. feature en masterDit komt omdat een andere branch bugfix is samengevoegd met master terwijl we aan deze PR werkten.
Dit creΓ«ert een situatie waarin de externe branch master een nieuwere versie heeft dan degene waarop we onze branch hebben gebaseerd. featureDoor dit kunnen we HEAD niet eenvoudig terugrollen master naar het einde van de branch. featureIn deze situatie moeten we ofwel een merge uitvoeren, of de commits feature bovenop toepassen (rebase). masterGitHub kan in feite automatische merges uitvoeren als er geen conflicten zijn. Helaas hebben beide takken in onze situatie concurrerende wijzigingen in het bestand. ci.mdDeze situatie staat bekend als een merge conflict, en we moeten dit handmatig oplossen.

Merge of rebase

Merge

  • CreΓ«ert een extra merge commit en behoudt de werkgeschiedenis.
    • Behoudt de oorspronkelijke commits van de takken met de oorspronkelijke tijdstempels en auteurs.
    • Behoudt de SHA van de commits en de verwijzingen naar hen in de discussies over pull requests.
  • Vereist eenmalige oplossing van conflicten.
  • Maakt de geschiedenis niet-lineair.
    • De geschiedenis kan moeilijk te lezen zijn vanwege het aantal takken (vergelijkbaar met een IDE-kabel).
    • Verhoogt de complexiteit van automatische debugging, bijvoorbeeld door het git bisect minder nuttig te maken β€” het vindt alleen de merge commit.

Rebase

  • Herkent de commits van de huidige tak één voor één op de basis.
    • Er worden nieuwe commits met nieuwe SHA's gecreΓ«erd, waardoor de commits in GitHub overeenkomen met de oorspronkelijke pull requests, maar niet met de bijbehorende opmerkingen.
    • Commits kunnen tijdens dit proces opnieuw worden gecombineerd en gewijzigd of zelfs in één worden samengevoegd.
  • Het kan nodig zijn om meerdere conflicten op te lossen.
  • Stelt je in staat om een lineaire geschiedenis te behouden.
    • De geschiedenis kan gemakkelijker te lezen zijn, tenzij deze te lang is zonder goede reden.
    • Automatische debugging en probleemoplossing is iets eenvoudiger: maakt het mogelijk om git bisect, kan automatische rollbacks duidelijker en voorspelbaarder maken.
  • Vereist het publiceren van takken met geleide commits met de vlag --force bij het gebruik met pull requests.

Meestal stemmen teams altijd in om dezelfde strategie te gebruiken wanneer ze wijzigingen moeten samenvoegen. Dit kan een "schone" merge of "schone" toepassing van commits zijn of iets er tussenin, zoals het uitvoeren van de toepassing van commits in interactieve modus (git rebase -i) lokaal voor takken die niet in de gedeelde repository zijn gepubliceerd, maar een merge voor "publieke" takken.

Hier zullen we merge gebruiken.

️ Taak

  1. Zorg ervoor dat de code in de lokale tak master is bijgewerkt vanuit de externe repository.
  2. auth0 feature.
  3. InitiΓ«ren van de merge met de tak master. Er zal een melding zijn van een merge conflict met betrekking tot concurrerende wijzigingen in ci.md.
  4. Los het conflict op zodat onze CI-stappenlijst en de opmerking daarover in de tekst blijft.
  5. Publiceer de merge commit naar de remote branch feature.
  6. Controleer de status van de pull request in de GitHub-gebruikersinterface en wacht tot de merge is opgelost.

Teams

# Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ΄ Π² локальноС Π²Π΅Ρ‚ΠΊΠ΅ `master` ΠΎΠ±Π½ΠΎΠ²Π»Ρ‘Π½ ΠΈΠ· ΡƒΠ΄Π°Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ рСпозитория.
git checkout master
git pull

# ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ Π½Π° Π²Π΅Ρ‚ΠΊΡƒ feature
git checkout feature

# Π˜Π½ΠΈΡ†ΠΈΠΈΡ€ΡƒΠΉΡ‚Π΅ слияниС с Π²Π΅Ρ‚ΠΊΠΎΠΉ master 
git merge master

# A merge conflict related to concurrent changes to ci.md will be reported
# => Auto-merging ci.md
#    CONFLICT (content): Merge conflict in ci.md
#    Automatic merge failed; fix conflicts and then commit the result.

# Π Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈ наш список шагов CI, ΠΈ Π·Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅ ΠΎ Π½Π΅ΠΌ ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ Π² тСкстС.
# ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ci.md Ρ‡Ρ‚ΠΎΠ± ΠΎΠ½ Π½Π΅ содСрТал ΠΌΠ°Ρ€ΠΊΠ΅Ρ€ΠΎΠ² ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Π° слияния
git add ci.md
git merge --continue
# ΠΏΡ€ΠΈ ΠΊΠΎΠΌΠΌΠΈΡ‚Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ сообщСниС ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ

# ΠžΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠΉΡ‚Π΅ ΠΊΠΎΠΌΠΌΠΈΡ‚ слияния Π² ΡƒΠ΄Π°Π»Π΅Π½Π½ΡƒΡŽ Π²Π΅Ρ‚ΠΊΡƒ feature.
git push

# ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ статус запроса Π½Π° измСнСния Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС GitHub, Π΄ΠΎΠΆΠ΄ΠΈΡ‚Π΅ΡΡŒ ΠΏΠΎΠΊΠ° слияниС Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ.

Goed werk!

Je hebt het werk met de lijst afgerond en nu moet je de pull request goedkeuren in master.

️ Taak: Keur de pull request "Steps review" goed

  1. Open de pull request.
  2. Klik op "Merge pull request".
  3. Klik op "Bevestig de samenvoeging".
  4. Klik op "Delete branch", omdat we deze niet meer nodig hebben.

Dit is je repository op dit moment
Typische situaties bij continue integratie

Fout op productie

Men zegt dat "testen kan worden gebruikt om de aanwezigheid van fouten aan te tonen, maar nooit om de afwezigheid ervan te bewijzen". Hoewel we tests hadden en deze ons geen fouten toonden, heeft een slinkse fout zich toch in de productie genesteld.

In een dergelijk scenario moeten we zorgen voor:

  • wat op productie is uitgerold;
  • de code in de branch master met de fout, waarmee ontwikkelaars opnieuw aan de slag kunnen.

Rollback of corrigeren in de volgende versie?

"Rollbacken" is het uitrollen van een eerder erkende en correcte versie in de productieomgeving en het terugdraaien (revert) van commits die de fout bevatten. "Corrigeren in de volgende versie" is het toevoegen van een oplossing in master en het zo snel mogelijk uitrollen van een nieuwe versie. Aangezien API's en databaseschema's veranderen terwijl code in de productieomgeving wordt uitgerold, en met continue levering en goede testdekking, is rollbacken over het algemeen veel complexer en risicovoller dan corrigeren in de volgende versie.

Aangezien rollbacken in ons geval geen risico met zich meebrengt, kiezen we hiervoor, omdat het ons in staat stelt

  • de fout op productie zo snel mogelijk te verhelpen;
  • de code in master direct geschikt te maken voor nieuwe werkzaamheden.

️ Taak

  1. auth0 master lokaal.
  2. Werk je lokale repository bij vanuit de remote repository.
  3. Annuleer de merge commit van de PR Stappenreview in master.
  4. Publiceer de wijzigingen naar de remote repository.

Dit is de geschiedenis van de repository met de geannuleerde merge commit
Typische situaties bij continue integratie

Teams

# ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ Π½Π° Π²Π΅Ρ‚ΠΊΡƒ master.
git checkout master

# ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΈΠ· ΡƒΠ΄Π°Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ рСпозитория.
git pull

# ΠžΡ‚ΠΌΠ΅Π½ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠΌΠΈΡ‚ слияния PR Steps review Π² master.
# ΠœΡ‹ отмСняСм ΠΊΠΎΠΌΠΌΠΈΡ‚ слияния, поэтому Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Π²Π΅Ρ‚ΠΊΡƒ истории, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΌΡ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΠΌ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ
git show HEAD

# ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠΌΠΌΠΈΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±Ρ‹Π» послСдним Π² Π²Π΅Ρ‚ΠΊΠ΅ master Π΄ΠΎ слияния, Π±Ρ‹Π» ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΡ‘Π½ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ
git revert HEAD -m 1
# ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ сообщСния ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΎΠ²

# ΠžΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠΉΡ‚Π΅ измСнСния Π² ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ
git push

️ Zelfcontrole

Zorg ervoor dat ci.md er geen tekst "sneaky bug" meer aanwezig is na het annuleren van de merge commit.

Corrigeer de CI-stappenlijst en breng deze terug naar master

We hebben de merge commit van de branch volledig teruggedraaid feature. Het goede nieuws is dat we nu geen fout meer hebben in masterHet slechte nieuws is dat onze waardevolle lijst met stappen voor continue integratie is verdwenen. Dus idealiter moeten we een oplossing toepassen op de commits van feature en ze terugbrengen naar master met de oplossing.

We kunnen de taak op verschillende manieren benaderen:

  • het commit annuleren (revert) dat de merge terugdraait feature met master;
  • de commits van de oude tak verplaatsen feature.

Verschillende ontwikkelingsteams gebruiken verschillende benaderingen in dit geval; wij zullen de nuttige commits naar een aparte tak verplaatsen en een aparte pull request voor deze nieuwe tak aanmaken.

️ Taak

  1. Maak een tak genaamd feature-fix en schakel naar deze tak.
  2. Verplaats alle commits van de oude tak feature naar de nieuwe tak. Los de merge-conflicten op die zijn ontstaan tijdens het verplaatsen.

    Typische situaties bij continue integratie

  3. Voeg een regressietest toe in ci.test.js:

    it('bevat de verborgen bug niet', () => {
    expect( /.*sneaky bug.*/gi.test(fileContents)).toBe(false);
    });

  4. Voer de tests lokaal uit om te zorgen dat ze niet succesvol eindigen.
  5. Verwijder de tekst " with a sneaky bug" in ci.md.
  6. Voeg de wijzigingen in de tests en de wijzigingen in de lijst met stappen toe aan de index en commit ze.
  7. Publiceer de tak naar de externe repository.

U zou uiteindelijk iets vergelijkbaars moeten hebben
Typische situaties bij continue integratie

Teams

# Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ feature-fix ΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ Π½Π° Π½Π΅Π΅.
git checkout -b feature-fix

# ΠŸΠ΅Ρ€Π΅Π½Π΅ΡΠΈΡ‚Π΅ всС ΠΊΠΎΠΌΠΌΠΈΡ‚Ρ‹ ΠΈΠ· Π±Ρ‹Π²ΡˆΠ΅ΠΉ Π²Π΅Ρ‚ΠΊΠΈ feature Π² Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ‚ΠΊΡƒ. Π Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Ρ‹ слияния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ»ΠΈ ΠΏΡ€ΠΈ пСрСносС.
# ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΈΡΡ‚ΠΎΡ€ΠΈΡŽ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ Ρ…ΡΡˆΠΈ ΠΊΠΎΠΌΠΌΠΈΡ‚ΠΎΠ²:
# - ΠΏΡ€Π΅Π΄ΡˆΠ΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΊΠΎΠΌΠΌΠΈΡ‚Ρƒ с ΠΏΠ΅Ρ€Π²ΠΎΠΉ Ρ‡Π°ΡΡ‚ΡŒΡŽ списка: C0
# - Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‰Π΅Π³ΠΎ послСдниС элСмСнты списка: C2
git log --oneline --graph
git cherry-pick C0..C2
# Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Ρ‹ слияния
# - ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠΉΡ‚Π΅ ci.md ΠΈ/ΠΈΠ»ΠΈ ci.test.js
# - Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π² индСкс
# - Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ "git cherry-pick --continue", ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π΅ ΠΌΠ΅Π½ΡΡ‚ΡŒ сообщСниС ΠΊΠΎΠΌΠΌΠΈΡ‚Π°

# Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ рСгрСссионный тСст Π² ci.test.js
# ЗапуститС тСсты локально, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ Π½Π΅ Π·Π°Π²Π΅Ρ€ΡˆΠ°ΡŽΡ‚ΡΡ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ.

# Π£Π΄Π°Π»ΠΈΡ‚Π΅ тСкст " with a sneaky bug" Π² ci.md.

# Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π² индСкс измСнСния тСстов ΠΈ Π² спискС шагов ΠΈ Π·Π°ΠΊΠΎΠΌΠΌΠΈΡ‚ΡŒΡ‚Π΅ ΠΈΡ….
git add ci.md ci.test.js
git commit -m "Fix the bug in steps list"

# ΠžΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠΉΡ‚Π΅ Π²Π΅Ρ‚ΠΊΡƒ Π² ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ.
git push --set-upstream origin feature-fix

Maak een pull request.

CreΓ«er een pull request met de titel Fixing the feature. Stel in feature-fix zoals "head branch", en master als 'base branch'.
Gelieve te wachten totdat de tests zijn voltooid. U kunt de status van de tests onderaan de PR-discussie zien.

Zorg ervoor dat je master in je fork van de repository als 'base branch' hebt ingesteld, ik zal geen wijzigingen in de repository met cursusmaterialen accepteren.

Goedkeur de pull request "Fixing the feature"

Bedankt voor de correctie! Gelieve de wijzigingen in master uit de pull request goed te keuren.

️ Taak

  1. Klik op "Merge pull request".
  2. Klik op "Bevestig de samenvoeging".
  3. Klik op "Delete branch", omdat we deze niet meer nodig hebben.

Dit is wat je op dit moment zou moeten hebben
Typische situaties bij continue integratie

Gefeliciteerd!

U heeft alle stappen uitgevoerd die mensen doorgaans in het proces van continue integratie nemen.

Als u problemen met de cursus opmerkt of weet hoe deze te verbeteren, maak dan een issue aan in de repository met cursusmateriaal. Deze cursus heeft ook een interactieve versie die GitHub Learning Lab als platform gebruikt.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers πŸ”₯ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster