Ga naar inhoud

Nieuwe functionaliteit bouwen

Nieuwe functionaliteit is een wijziging in de coderepository. Een wijziging die alleen andere waarden nodig heeft, is een configuratiewijziging; zie Config. Elke nieuwe feature volgt de regels voor achterwaartse compatibiliteit: opt-in, standaard uit.

flowchart LR
    a["1. Module"] --> b["2. Koppel aan een layer<br/>+ feature flag"]
    b --> c["3. Test"]
    c --> d["4. Deploy naar dev<br/>(lokaal / Demo canary)"]
    d --> e["5. PR + CI"]
    e --> f["Release"]

0. Je omgeving inrichten

  1. Clone xms-cloud-platform-code en open het in de dev container (VS Code: Reopen in Container). Daarin zitten PowerShell 7, Terraform, de Azure CLI en Pester.
  2. De dev container mount ../config, relatief aan de coderepository, op /workspaces/config. Clone een configuratierepository naast de code als config, of gebruik de Demo-configuratie in config/Demo/canary.
  3. Kopieer .env.example naar .env en stel MCP_CONFIG in, bijvoorbeeld MCP_CONFIG=/workspaces/xms-cloud-platform-code/config/Demo/canary/mcp.json.
  4. Installeer de git hooks: lefthook install.
  5. Maak een branch vanaf main. feature/<name> krijgt een GitVersion-label (-<name>); users/<initials>/<name> is de gebruikelijke conventie voor persoonlijk werk.

1. Modules

Terraform is georganiseerd in drie niveaus:

Level Map Regel
Module infra/modules/<name>/ Eén resourcetype of een nauw samenhangende groep. Geen kennis van layers of configbestanden. Bestanden: main.tf, variables.tf, output.tf/outputs.tf, versions.tf, optioneel tests/.
Template infra/templates/<name>/ Combineert modules tot een feature (bijvoorbeeld application_gateway, virtual_hub). Berekent namen uit de scaffold_* variabelen.
Layer infra/deploy/<layer>/ Root module met backend, providers en variabelen. Roept templates aan achter feature flags. Variabelen zijn per feature opgesplitst: variables_<feature>.tf.

Richtlijnen (zie ook .agents/skills/terraform-style-guide in de coderepository):

  • Draai terraform fmt. Gebruik create_* / use_*_module booleans voor optionele features en *_id inputs voor afhankelijkheden.
  • Gebruik dynamic blocks voor optionele geneste configuratie.
  • Bouw namen op uit scaffold_company_short_name, scaffold_environment en scaffold_location_short_name, en voeg een overwrite_*_name variabele toe zodat klanten met bestaande namen die kunnen behouden.
  • Als de feature JSON uit de configuratierepository leest, neem dan een *_relative_path variabele en bouw het pad op als "${var.config_path}/${var.<x>_relative_path}". Onthoud dat fileset() op een verkeerd pad niets teruggeeft.
  • Pin providers in root modules op een exacte versie. Anders faalt de pin check.

Spoke-features

Spoke Terraform staat in src/Xebia.Mcp/Files/terraform/spoke-canvas/ (deploy/subscription, deploy/spoke, modules/). Een nieuwe spoke-property vraagt om:

  1. de Terraform die de property leest, met een default als de property ontbreekt;
  2. een optionele property in src/Xebia.Mcp/Files/json/spokeschema.json;
  3. een rij in de spoke-JSON-referentie.

2. Koppel het aan een layer, achter een flag

# infra/deploy/connectivity/variables_my_feature.tf
variable "use_my_feature_module" {
  description = "Deploy my feature. Default false keeps existing deployments unchanged."
  type        = bool
  default     = false
}

# infra/deploy/connectivity/main.tf
module "my_feature" {
  source = "../../templates/my_feature"
  count  = var.use_my_feature_module ? 1 : 0
  # ...
}

Daarna:

  • voeg de flag en de bijbehorende variabelen toe aan de Demo-configuratie (config/Demo/canary/<region>/<layer>.auto.tfvars);
  • voeg de flag toe aan de feature flags-referentie;
  • als consumenten of operators erom gaan vragen, voeg dan een runbook toe of breid er een uit onder Veelvoorkomende aanvragen;
  • als de beslissing architecturaal is, schrijf dan een ADR (docs/adr/, template adr-template.md).

Wijzigingen in de orkestratie

Logica die bepaalt wat er draait (if/else, loops, matrices, parsing) hoort in een PowerShell-functie in src/Xebia.Mcp/Functions/, niet in YAML (ADR-0011, CONTRIBUTING.md):

  • Publieke functies in Functions/Public/<Domain>/, interne in Functions/Private/<Domain>/.
  • Comment-based help met .SYNOPSIS, .DESCRIPTION, .PARAMETER, .EXAMPLE, .NOTES.
  • begin/clean blocks die begin.ps1 / clean.ps1 dot-sourcen.
  • Wijzig het Azure DevOps-template en de GitHub workflow in dezelfde pull request.

3. Testen

Test Waar Hoe te draaien Draait in
Terraform validate + docs elke layer automatisch bij commit lefthook pre-commit
Terraform moduletests infra/modules/<name>/tests/*.tftest.hcl (met mock_provider) terraform -chdir=infra/modules/<name> test, of automatisch voor gestagede modules (scripts/Run-TerraformTest.ps1) lefthook pre-commit
Provider pin check infra/deploy/** pwsh scripts/Test-TerraformRootProviderPins.ps1 lefthook + GitHub CI
PowerShell unit tests Functions/**/Tests/<Function>.Unit.Tests.ps1 pwsh ./dev/dev.ps1 -Action Test Prepare-stap van elke pipeline
Pariteitscontroles module-breed (bestandsnaam = functienaam, elke publieke functie heeft een unit test, …) pwsh ./dev/dev.ps1 -Action Test Prepare-stap
Config tests src/Xebia.Mcp/Tests/{Config,SpokeConfig,Smoke} pwsh ./dev/dev.ps1 -Action Test (gebruikt MCP_CONFIG) Prepare-stap van elke pipeline

Elke publieke functie heeft een unit test nodig; Assert-XebiaPublicFunctionUnitTestParity faalt anders. Mock aanroepen van de Azure CLI en Terraform.

4. Deployen naar dev

Het ontwikkeldoel is de Demo tenant, configuratie config/Demo/canary in de coderepository.

Lokaal (snelle feedback, je eigen Azure-login):

Import-Module ./src/Xebia.Mcp/Xebia.Mcp.psd1 -Force
Initialize-XebiaDotEnv
Sync-XebiaInfraToMcpModule -Mappings @(@{ Description = 'cloud-platform'; Source = './infra'; Target = 'terraform/cloud-platform/' }) -WhatIf:$false
$config = Resolve-XebiaMcpConfiguration -Path $env:MCP_CONFIG

# Plan one layer (WhatIf on: plan, no apply) — same as dev.ps1 does by default
$global:WhatIfPreference = $true
Deploy-XebiaLocal -Config $config -DeployName connectivity -Region weu

# Plan and apply
$global:WhatIfPreference = $false
Deploy-XebiaLocal -Config $config -DeployName connectivity -Region weu

(dev/dev.ps1 -Action HubDeploy is de bedoelde shortcut, maar werkt niet op main, zie Bekende problemen.)

Via workflow/pipeline (zoals klanten): draai de eigen entry pipelines van de coderepository (hub.yaml, spoke.yaml) vanaf je branch tegen de Demo-configuratie. Gebruik mode: Plan of ApproveModifications.

Controleer twee dingen:

  1. Met de flag uit: het plan toont geen wijzigingen. Dit bewijst achterwaartse compatibiliteit.
  2. Met de flag aan: het plan toont alleen de nieuwe resources, en de apply werkt.

5. Pull request en CI

  1. Commit met Conventional Commits (feat(connectivity): add …, fix(ps): …), in Amerikaans Engels (docs/coding-standards/).
  2. Open een pull request naar main. Beschrijf de wijziging en de flag, en koppel het work item.
  3. Zet de versieverhoging in de merge message: +semver: minor voor een feature, +semver: patch voor een fix, +semver: major voor een breaking change, +semver: none voor alleen docs. Zie Releasen.
  4. CI draait:

    Platform Pipeline Wat het doet
    Azure DevOps pull-request.yaml (PR naar main) Bouwt de container vanaf de PR-branch en draait daarna de hub-stages (deploy en destroy) en spoke-stages (deploy en destroy, glob **/*str*.json) in Plan / WhatIf tegen canary
    GitHub ci.yml (PR die infra/deploy/** raakt) Provider pin check
  5. Een reviewer controleert: flag standaard uit, moved blocks voor hernoemingen, unit tests, zowel ADO als GitHub aangepast, docs bijgewerkt.

  6. Merge. Moet de fix ook naar een ondersteunde versie, cherry-pick hem dan naar de release/vX.Y branch (zie Releasen).