Naar de hoofdinhoud

Migreren van Azure DevOps naar fremforge

Deze gids beschrijft de migratie van Azure DevOps Services (dev.azure.com) naar fremforge. De migratie vanaf Azure DevOps Server (on-premises) is vergelijkbaar, maar de details van authenticatie en API-endpoints verschillen. Pas de onderdelen hieronder over tokens en endpoints aan voor jouw specifieke installatie.

Van de drie grote migratiebronnen verschilt Azure DevOps qua structuur het meest. ADO heeft aparte producten voor Repos, Pipelines, Boards, Test Plans en Artifacts; fremforge levert Repos + CI/CD + Artifacts + eenvoudige issues als één geïntegreerd geheel en heeft geen tegenhangers voor Test Plans of de volledige functieset van Boards. Een ADO-migratie is daarom deels ook een beslissing over de reikwijdte, naast een technische migratie: voor sommige ADO-functies waarop je misschien leunt, bestaat bij fremforge geen bestemming.

Ontbrekende functies

fremforge heeft geen tegenhangers voor: werkitems van Azure Boards (geen issuehiërarchie of sprintplanning), Test Plans (geen beheer van testgevallen), het automatisch migreren van Azure Artifacts-feeds (pakketten moeten opnieuw worden gepubliceerd) en Classic pipelines (YAML-pipelines migreren wel; designer-pipelines niet). Zijn dit blokkades, bekijk dan de reikwijdte van de migratie voordat je begint.

Lees eerst de gids voor migratie vanaf GitHub en de gids voor migratie vanaf GitLab als je dat nog niet hebt gedaan. Een aantal basisstappen (SSH-sleutels, integraties van derden) is identiek en herhalen we hier niet volledig.

Voordat je begint

Wat je zelf nodig hebt:

  • De rol Project Administrator op het Azure DevOps-project (of de projecten) dat je migreert.
  • Een personal access token op ADO met minimaal de scopes Code (Read), Code (Status), Work Items (Read), Build (Read), Release (Read) en Identity (Read).
  • Beheerderstoegang tot de fremforge-organisatie waarnaar je migreert.
  • Voor de migratie van Pipelines: een overzicht van de YAML-pipelinebestanden, eventuele classic (niet-YAML-)pipelines, service connections (die worden OIDC-federatie), variable groups en agent pools waarvan je afhankelijk bent.

Wat we aanraden:

  • Zet classic (niet-YAML-)pipelines in ADO om naar YAML-pipelines voordat je migreert. Migreren van classic pipelines naar Forgejo Actions komt neer op alles opnieuw schrijven; eerst naar YAML omzetten geeft je een overdraagbaar startpunt en verbetert ook je ADO-opzet.
  • Ga na welke typen werkitems in Boards je echt gebruikt. fremforge (Forgejo) heeft issues en mijlpalen, maar geen Epics, Features, User Stories of Tasks als aparte typen. Die worden allemaal issues met labels. Hangt je werkwijze af van de hiërarchie van werkitemtypen, plan dat samenvoegen dan vóór de migratie.
  • Breng afhankelijkheden van Test Plans in kaart. fremforge heeft geen directe tegenhanger; teams die sterk op ADO Test Plans leunen, laten ADO Test Plans meestal als aparte tool doorlopen of stappen over op een speciale tool voor testbeheer.

Geschatte tijd:

  • Eén repository met een eenvoudige pipeline en beperkt gebruik van Boards: 1-2 uur.
  • Repository met een gemiddeld complexe pipeline en release-pipelines met meerdere stages: 3-6 uur.
  • Migratie van een hele organisatie met veel pipelines, variable groups en service connections: 1-2 weken engineering, grotendeels voor het omzetten van pipelines en het vervangen van service connections.

Stap 1: Repository en geschiedenis migreren

De ingebouwde importer van Forgejo ondersteunt Azure DevOps als bron. Hij kopieert de Git-geschiedenis en, afhankelijk van je ADO-configuratie, werkitems (geïmporteerd als issues) en pull requests.

Met de ingebouwde importer (via de UI)

Vanuit de beheer-UI van fremforge:

  1. Klik op + → Nieuwe migratie.
  2. Kies Azure DevOps als bron.
  3. Plak de URL van de repository (bijvoorbeeld https://dev.azure.com/acme/project/_git/backend).
  4. Plak je personal access token van ADO.
  5. Vink de soorten inhoud aan die je wilt importeren.
  6. Kies de doelorganisatie en de naam van de repository.
  7. Klik op Migreer repository.

Via de API (scriptbaar)

# Build the JSON body via jq so the PAT is JSON-string-escaped safely
# (Azure DevOps PATs can contain `/`, `+`, `=` characters which are
# fine in JSON strings but a raw shell-interpolation can still break
# if the PAT happens to contain `"` from a copy-paste error).
jq -nc \
  --arg clone_addr    "https://dev.azure.com/acme/project/_git/backend" \
  --arg auth_username "fremforge" \
  --arg auth_token    "$ADO_TOKEN" \
  --arg repo_owner    "acme" \
  --arg repo_name     "backend" \
  '{clone_addr: $clone_addr, auth_username: $auth_username, auth_token: $auth_token,
    service: "git", repo_owner: $repo_owner, repo_name: $repo_name,
    issues: false, pull_requests: false, lfs: true}' \
| curl -X POST "https://frem.sh/api/v1/repos/migrate" \
    -H "Authorization: Bearer ${FREMFORGE_TOKEN}" \
    -H "Content-Type: application/json" \
    -d @-

Let op: ADO is geen van de service-waarden die Forgejo voor migraties herkent. De enum op protocolniveau in upstream Forgejo is git, github, gitea, gitlab, gogs, onedev, gitbucket, codebase; git is de terugvaloptie voor gewone Git (sommige oudere documentatie noemt het “plain”, maar de waarde op protocolniveau is letterlijk de string git). "service": "git" expliciet instellen (zoals in de body hierboven) is de canonieke waarde; de ADO-PAT in auth_token zorgt voor de authenticatie, en de clone-URL is een gewone HTTPS-git-remote die de importer voor gewone Git correct afhandelt. Met "lfs": true haalt de importer LFS-objecten op via het LFS-endpoint van de bron; dat is nodig voor ADO-repository’s met LFS-inhoud. Werkitems en PR-metadata importeer je daarna apart met een gescripte workflow op de REST-API van ADO (zie hieronder); de importer voor gewone Git neemt alleen refs mee.

auth_username is verplicht voor ADO. PAT’s van Azure DevOps gebruiken HTTP Basic Auth, waarbij het wachtwoord de PAT is en de gebruikersnaam een willekeurige niet-lege string moet zijn (Microsoft-documentatie: “When using a PAT, the username can be any non-empty string”). Anders bouwt de importer voor gewone Git van Forgejo URL’s in de vorm https://{auth_token}@…, die de Git-server van AzDO als gebruikersnaam leest en met 401 weigert. Gebruik "auth_username": "fremforge" (of een andere niet-lege string; de waarde maakt AzDO niet uit, alleen de vorm van de Basic Auth).

ADO-begrippen in fremforge

Begrip in Azure DevOpsBegrip in fremforge (Forgejo)
Organisation(geen directe tegenhanger, meestal één fremforge-organisatie per ADO-organisatie)
ProjectOrganisatie, of een voorvoegsel in de namen van repository’s
RepositoryRepository
Pull RequestPull request
Work Item: Epic, Feature, User Story, Task, BugIssue met label (epic, feature, story, task, bug)
Area PathLabel of eigen mijlpaal
Iteration PathMijlpaal
Build PipelineForgejo Actions-workflow
Release PipelineForgejo Actions-workflow met jobs per deploymentomgeving
Service ConnectionConfiguratie voor OIDC-federatie
Variable GroupOmgevingssecrets op organisatie- of omgevingsniveau
Agent PoolRunnerlabel / groep eigen runners (BYO)
Test Plan / Test SuiteGeen functie van fremforge, externe tool
Artifact FeedPakketregister van fremforge
WikiWiki

Werkitems → issues

Werkitems worden niet geïmporteerd door de ingebouwde importer van Forgejo. Migratiescript:

#!/bin/bash
# Requires: curl, jq, ADO_TOKEN, FREMFORGE_TOKEN
ADO_ORG="acme"
ADO_PROJECT="project"
FREMFORGE_ORG="acme"
FREMFORGE_REPO="backend"

# Query all work items in the project
curl -s -u ":${ADO_TOKEN}" \
  "https://dev.azure.com/${ADO_ORG}/${ADO_PROJECT}/_apis/wit/wiql?api-version=7.1" \
  -H "Content-Type: application/json" \
  -d '{"query":"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject]=@project"}' \
  | jq -r '.workItems[].id' \
  | while read wi_id; do
    # Fetch full work item
    ado_wi=$(curl -s -u ":${ADO_TOKEN}" \
      "https://dev.azure.com/${ADO_ORG}/_apis/wit/workitems/${wi_id}?api-version=7.1")

    title=$(echo "${ado_wi}" | jq -r '.fields."System.Title"')
    body=$(echo "${ado_wi}" | jq -r '.fields."System.Description" // ""')
    wi_type=$(echo "${ado_wi}" | jq -r '.fields."System.WorkItemType"' | tr '[:upper:]' '[:lower:]')
    state=$(echo "${ado_wi}" | jq -r '.fields."System.State"')

    # Create fremforge issue
    curl -s -X POST "https://frem.sh/api/v1/repos/${FREMFORGE_ORG}/${FREMFORGE_REPO}/issues" \
      -H "Authorization: Bearer ${FREMFORGE_TOKEN}" \
      -H "Content-Type: application/json" \
      -d "{
        \"title\": \"${title}\",
        \"body\": \"**Migrated from Azure DevOps work item #${wi_id}**\n\n${body}\",
        \"labels\": [\"${wi_type}\"],
        \"closed\": $([[ "${state}" == "Closed" || "${state}" == "Done" || "${state}" == "Resolved" ]] && echo true || echo false)
      }"
  done

Pas het aan waar nodig. Dit is een startpunt, geen kant-en-klare oplossing. Bij grote migraties voeg je backoff bij rate limits en het behouden van opmerkingen toe.

Paginering in WIQL. Azure DevOps begrenst één WIQL-antwoord op 20.000 werkitems. Het script hierboven doet één query en loopt die resultaatset door; voor het gangbare geval is dat prima. Tel eerst voordat je het start:

COUNT=$(curl -s -u ":${ADO_TOKEN}" \
  "https://dev.azure.com/${ADO_ORG}/${ADO_PROJECT}/_apis/wit/wiql?api-version=7.1" \
  -H "Content-Type: application/json" \
  -d '{"query":"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject]=@project"}' \
  | jq '.workItems | length')
echo "Work items in scope: ${COUNT}"

Ligt COUNT boven ongeveer 19.000, verdeel de query dan (bijvoorbeeld per kwartaal van [System.CreatedDate] of per [System.WorkItemType]) en voer het script per deel uit, of neem voor zeer grote aantallen werkitems contact op met support@frem.sh. De route met één query kapt bij de grens stilzwijgend af: er komt geen foutmelding, alleen een te korte resultaatset, en dat is precies de manier van falen die je tijdens een migratie niet wilt.

Stap 2: Secrets en variabelen

Plekken waar Azure DevOps secrets bewaart:

  • Pipelinevariabelen (inline in YAML): herschrijf je tijdens de migratie.
  • Variable Groups (op projectniveau, eventueel gekoppeld aan Azure Key Vault): maak je opnieuw aan als secrets op organisatie- of omgevingsniveau in fremforge.
  • Geheime variabelen (gemarkeerd als secret, niet teruggegeven door de ADO-API): moet je ophalen uit je leidende secretsopslag en opnieuw invoeren.
  • Verwijzingen naar Key Vault: is de variable group gekoppeld aan Azure Key Vault, dan kun je (a) Key Vault houden en de runners van fremforge via OIDC-federatie bij Azure laten authenticeren en de waarden tijdens de job laten ophalen, of (b) de waarden rechtstreeks naar secrets in fremforge kopiëren.

Sterk aangeraden: vervang secrets van Azure-service-principals door OIDC-federatie naar Azure (zie stap 4).

Stap 3: Pipelines omzetten naar Forgejo Actions

YAML voor Azure Pipelines en YAML voor Forgejo Actions lijken qua vorm op elkaar, maar gebruiken een flink andere woordenschat. Het omzetten gaat met de hand. Automatisch omzetten is uitgesteld naar fase 2, afhankelijk van de vraag van klanten.

Omzettingspatronen

Stages en jobs

YAML voor Azure Pipelines:

trigger: [main]

stages:
  - stage: Build
    jobs:
      - job: BuildApp
        pool:
          vmImage: ubuntu-latest
        steps:
          - script: make build
            displayName: 'Build'

  - stage: Test
    dependsOn: Build
    jobs:
      - job: TestApp
        pool:
          vmImage: ubuntu-latest
        steps:
          - script: make test
            displayName: 'Test'

De tegenhanger in Forgejo Actions:

name: CI

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: fremforge
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: make build

  test:
    needs: build
    runs-on: fremforge
    steps:
      - uses: actions/checkout@v4
      - name: Test
        run: make test

De belangrijkste omzettingen:

  • trigger: → on: push: met branchfilters.
  • pr: → on: pull_request:.
  • schedules: → on: schedule: met cron-expressies.
  • stages / jobs / steps → jobs / steps (één niveau platter; stages heeft geen directe tegenhanger, de volgorde bereik je met needs: tussen jobs).
  • pool: vmImage: ubuntu-latest → runs-on: fremforge (zie Runner-images voor het besturingssysteem van de runner, de lijst met vooraf geïnstalleerde tools en hoe je toolchains voor talen installeert met setup-*-actions).
  • script: → run: met hetzelfde shellcommando.
  • task: <name>@<version> → uses: <action-path>@<version>, waarbij de action een gelijkwaardige Marketplace-action is. De meeste ADO-tasks hebben geen directe tegenhanger in Forgejo Actions en worden herschreven als run:-stappen of kleine composite actions.

ADO-tasks die vaak omgezet moeten worden

ADO-taskVervanging in Forgejo Actions
UseNode@1actions/setup-node@v4
UsePythonVersion@0actions/setup-python@v5
UseDotNet@2actions/setup-dotnet@v4
UseJavaVersion@1actions/setup-java@v4
PublishBuildArtifacts@1actions/upload-artifact@v4
DownloadBuildArtifacts@0actions/download-artifact@v4
Cache@2actions/cache@v4
Docker@2 / DockerCompose@0docker/build-push-action@v6 of rechtstreeks de docker-CLI in run:
AzureCLI@2azure/cli@v2 met credentials via OIDC-federatie (zie stap 4)
AzureKeyVault@2Secrets van fremforge zelf (voorkeur) of azure/cli@v2 + az keyvault secret show
SonarCloudPrepare@1 / SonarCloudAnalyze@1sonarsource/sonarcloud-github-action@master
PublishTestResults@2dorny/test-reporter@v1 of een artifact-upload op jobniveau + handmatig een rapport genereren
HelmDeploy@0helm/helm-action@v1 of rechtstreeks de helm-CLI
KubernetesManifest@0azure/k8s-deploy@v5 (met OIDC-authenticatie)

Voorwaarden

condition: in ADO → if: in Forgejo Actions.

ADO:

- task: Deploy
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))

Forgejo Actions:

- name: Deploy
  if: success() && github.ref == 'refs/heads/main'
  run: make deploy

Templates en Library

Templates in ADO (extends:, template:) komen overeen met herbruikbare workflows in Forgejo Actions (uses: <repo>/.forgejo/workflows/template.yaml@ref) of composite actions (uses: ./.forgejo/actions/<name>). Het omzetten gaat met de hand, maar is mechanisch werk.

Release-pipelines met meerdere stages → deployjobs met een omgevingspoort

Release-pipelines in ADO met goedkeuringspoorten komen overeen met Forgejo Actions-workflows die environment: <name> gebruiken om op omgevingsniveau de flow met verplichte reviewers / goedkeuring te starten. Stel de beveiligingsregels van de omgeving in via de beheer-UI van fremforge op Organisatiebeheer → Omgevingen → <name>.

Agent pools → runnerlabels

pool: vmImage: windows-latest in ADO → runs-on: windows-latest in Forgejo Actions. De gehoste runners van fremforge zijn alleen Linux amd64. Windows en macOS zijn niet beschikbaar in het standaardabonnement.

Hebben je pipelines Windows- of macOS-runners nodig, dan zijn er twee routes:

  1. Eigen runners (BYO): registreer een Windows- of macOS-runner op je eigen infrastructuur met het label windows-latest of macos-latest. Je pipelines sturen ernaar via runs-on:.
  2. Die pipelines op ADO laten: voor teams die het grootste deel van hun CI migreren, maar Windows/Mac-builds op hun bestaande infrastructuur houden. Niet ideaal, maar als overgangssituatie ondersteund.

Stap 4: Service connections → OIDC-federatie

Azure DevOps gebruikt service connections om cloudcredentials op te slaan. fremforge vervangt die door OIDC-federatie, de voorkeursaanpak voor elk clouddoel, niet alleen Azure.

Voor Azure

  1. Maak in Azure AD een App Registration aan en stel een federated credential in met:
    • Issuer: https://frem.sh/_app/runner/oidc (één globale issuer voor alle tenants; zie build/runners/oidc/ voor het JWKS-endpoint en de volledige, met GitHub Actions compatibele set claims)
    • Subject: repo:<fremforge-org>/<repo>:ref:refs/heads/main (of het patroon voor afbakening dat je verkiest; de subject-claim bevat de organisatie, dus hier wordt de scheiding per tenant afgedwongen)
    • Audience: api://AzureADTokenExchange
  2. Geef de App Registration de benodigde roltoewijzingen op de Azure-doelabonnement(en).
  3. In je Forgejo Actions-workflow:
permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: fremforge
    steps:
      - uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
      - run: az account show

Geen client secret. Geen langlevende credential. Het token wordt tijdens de job uitgegeven, is beperkt tot deze workflow en verloopt binnen het uur.

Voor T Cloud Public

Net als bij migraties vanaf GitLab (GitLab, stap 4) ondersteunt fremforge OIDC-federatie naar agencies in T Cloud Public rechtstreeks. Stel dit in via de beheer-UI van fremforge op Instellingen → OIDC Federation.

Voor AWS / GCP

De standaardpatronen voor OIDC naar AWS en OIDC naar GCP werken net zo als vanuit GitHub Actions. Stel de vertrouwensrelatie in met https://frem.sh/_app/runner/oidc als issuer (één globale issuer voor alle tenants; leg in de voorwaarde van het vertrouwensbeleid de claim repository_owner vast voor scheiding per tenant, hetzelfde patroon als het repository_owner-filter van GitHub Actions op token.actions.githubusercontent.com).

Stap 5: SSH-sleutels opnieuw registreren

Zie stap 4 van de GitHub-migratie.

Stap 6: Boards migreren (gedeeltelijk)

Zoals gezegd heeft fremforge geen hiërarchie van werkitemtypen. Migratieopties:

  1. Platslaan: alle werkitems → issues met typelabels. Query’s en rapporten bouw je opnieuw op rond de zoekfunctie van fremforge.
  2. Boards apart houden: exporteer de ADO-werkitems naar een plat gegevensbestand, archiveer dat en blijf ADO Boards gebruiken voor backlogbeheer, terwijl je alleen code en CI migreert. Dat is een gangbare tussenoplossing voor teams die Boards intensief gebruiken.
  3. Vervangen door een speciale tool voor projectbeheer: Linear, Jira, Shortcut, GitHub Projects (als je in het GitHub-ecosysteem blijft maar ADO verlaat). De webhooks en REST-API van fremforge integreren met al deze tools.

Het importscript in stap 1 verzorgt optie 1 met platslaan op basis van labels.

Stap 7: Artifact-feeds → pakketregister van fremforge

Artifact-feeds van ADO komen overeen met het pakketregister van fremforge. Ondersteunde formaten op fremforge:

  • npm
  • Maven
  • Docker/OCI-containers
  • NuGet
  • PyPI
  • RubyGems
  • Composer
  • Go-modules
  • Generic

Migreren werkt via pushen: elke publicerende pipeline publiceert na de migratie de artifacts opnieuw naar het register van fremforge. Historische versies van artifacts op ADO blijven daar beschikbaar. Faseer ze uit in je eigen tempo.

Stap 8: Integraties van derden opnieuw koppelen

Zie stap 5 van de GitHub-migratie. ADO-specifieke integraties (Teams Service Hooks, ServiceNow, ADO-specifieke webhooks) koppel je opnieuw als webhooks van fremforge.

Stap 9: Verifiëren en uitfaseren

Hetzelfde als in de gids voor GitHub.

Veelvoorkomende valkuilen bij ADO-migraties

Classic pipelines kunnen niet automatisch worden gemigreerd.

Heb je classic (niet-YAML-)pipelines, zet ze dan eerst in ADO om naar YAML. Pas daarna de omzettingspatronen uit stap 3 toe. Sla je de tussenstap via YAML over, dan moet je pipelines opnieuw opbouwen vanuit de logische opzet in de ADO-UI, en dat is foutgevoelig.

Service connections met verwijzingen naar Azure Key Vault.

Een service connection die tijdens de uitvoering van de pipeline uit Azure Key Vault leest, vraagt om een migratie in twee stappen: (1) richt OIDC-federatie in zodat de runner van fremforge az login kan doen; (2) de workflow haalt het secret daarna tijdens de job op met az keyvault secret show, in plaats van het in secrets van fremforge op te nemen. Dat volgt het ADO-patroon precies.

Release-pipelines met goedkeuringspoorten.

Release-pipelines in ADO met handmatige goedkeuringspoorten vóór een productiedeploy komen overeen met Forgejo Actions met beveiligingsregels voor environment:. In de beheer-UI van fremforge stel je per omgeving verplichte reviewers in. De functionaliteit is gelijkwaardig; alleen de gebruikerservaring verschilt.

Afhankelijkheid van Test Plans.

Handmatige testuitvoering die in ADO Test Plans wordt bijgehouden, heeft bij fremforge geen bestemming. Teams die daarop leunen, moeten een vervangende tool kiezen (Xray voor Jira, Zephyr, qTest) of de kleinere reikwijdte accepteren.

Hulp krijgen

support@frem.sh met onderwerpregel MIGRATION, AZURE DEVOPS, <your-specific-issue>.


Zie ook: Gids voor migratie vanaf GitHub · Gids voor migratie vanaf GitLab · Compatibiliteitsmatrix van de top 20 Marketplace-actions · Checklist voor de migratie.