, , ,

Del caos multi-repo al orden: .NET Aspire + PolyRepo paso a paso

Avatar de David Oliva

Si tu plataforma vive en varios repos (frontend, backend y microservicios por separado), el día a día puede volverse caótico: clones manuales, soluciones “uber” llenas de pegamento y pipelines inconsistentes. .NET Aspire ya te da orquestación y observabilidad; con Aspire.PolyRepo añadimos el ingrediente que faltaba para poner orden: clonar repos y proyectar sus artefactos como recursos Aspire de forma declarativa.

  • Instala Dutchskull.Aspire.PolyRepo en tu AppHost.
  • Declara repos con AddRepository y proyecta artefactos con AddProjectFromRepository, AddNpmAppFromRepository o AddNodeAppFromRepository.
  • Conecta dependencias (WithReference) y expón puertos (WithHttpEndpoint). El Aspire Dashboard te muestra la topología y la salud.

La receta clásica era la “uber solution”: clonar varios repos y cablear proyectos a mano en una sola solución. Funciona, pero es repetitivo, frágil y difícil de estandarizar entre equipos.
Aspire.PolyRepo convierte ese proceso en configuración declarativa: el AppHost sabe qué repos clonar, dónde dejarlos y qué proyectos/apps exponer como recursos Aspire (con sus puertos y dependencias).

  • Clonado declarativo de repos Git (URL, rama por defecto, ruta de destino).
  • Proyección directa en el grafo de Aspire:
    • .NET → AddProjectFromRepository
    • npm → AddNpmAppFromRepository
    • Node → AddNodeAppFromRepository
  • Encaje con referencias y endpoints de Aspire: WithReference, WithHttpEndpoint, config compartida, etc.

dotnet add package Dutchskull.Aspire.PolyRepo

Define el repo, proyecta sus artefactos y conéctalos con el resto de piezas.

using Aspire.Hosting;

var builder = DistributedApplication.CreateBuilder(args);

// 1) Declarar el repo Git que quieres clonar
var repository = builder.AddRepository(
    "repository",
    "https://github.com/Dutchskull/Aspire-Git.git",
    cfg => cfg.WithDefaultBranch("feature/rename_and_new_api")
              .WithTargetPath("../../repos")); // carpeta central de clones (no versionada)

// 2) Proyectar un proyecto .NET del repo como recurso Aspire
var dotnetProject = builder
    .AddProjectFromRepository(
        "dotnetProject",
        repository,
        "src/Dutchskull.Aspire.PolyRepo.Web/Dutchskull.Aspire.PolyRepo.Web.csproj");

// 3) (Opcional) Proyectar una app npm y otra Node del mismo repo
var reactProject = builder
    .AddNpmAppFromRepository("reactProject", repository, "src/Dutchskull.Aspire.PolyRepo.React")
    .WithHttpEndpoint(3000);

var nodeProject = builder
    .AddNodeAppFromRepository("nodeProject", repository, "src/Dutchskull.Aspire.PolyRepo.Node")
    .WithHttpEndpoint(54622);

// (Opcional) Infra y dependencias
// var cache = builder.AddRedis("cache");
// dotnetProject.WithReference(cache);
// reactProject.WithReference(dotnetProject);

builder.Build().Run();


graph TD
    A["Dev: `dotnet run` (AppHost)"] --> B["AppHost (.NET Aspire)"]
    B --> C["Aspire.PolyRepo<br/>AddRepository / Add*FromRepository"]
    C --> D["Repos Git<br/>(orders-api, portal-ui, ... )"]
    D --> E["Workspace de clones<br/>`../../repos`"]

    E --> P1["Recurso: orders-api (.NET)<br/>AddProjectFromRepository(...)"]
    E --> P2["Recurso: portal-ui (npm/Node)<br/>AddNpmAppFromRepository(...)"]

    subgraph "Infra / Dependencias"
        DB["database"]
        CACHE["cache"]
    end

    P2 -- HTTP --> P1
    P1 --> DB
    P1 --> CACHE

    B --> DASH["Aspire Dashboard"]

    classDef res fill:#f5f5f5,stroke:#999,rx:6,ry:6
    class P1,P2,DB,CACHE,DASH res

Al ejecutar el AppHost, clona los repos en la ruta indicada y expone cada artefacto como recurso Aspire listo para compilar, arrancar y observar en el Dashboard.

Este flujo resume lo que pasa de extremo a extremo:

sequenceDiagram
    participant Dev as Dev
    participant AH as AppHost (.NET Aspire)
    participant PR as Aspire.PolyRepo
    participant Git as Servidor Git
    participant Build as MSBuild / NPM
    participant Svc as Recursos Aspire
    participant Dash as Aspire Dashboard

    Dev->>AH: dotnet run
    AH->>PR: AddRepository + Add*FromRepository (rutas, rama)
    PR->>Git: git clone (rama por defecto)
    Git-->>PR: repo clonado en workspace
    AH->>Build: compila .csproj / instala y arranca npm
    AH->>Svc: levanta servicios (WithReference, endpoints)
    Svc-->>Dash: health, logs, topología
    Dev-->>Dash: observa/diagnostica

Repos y ramas

  • Usa una convención de ramas por servicio y fija WithDefaultBranch a main o release/*.
  • Mantén rutas de proyecto estables dentro de cada repo para minimizar cambios en el AppHost.

Rutas y workspace

  • Centraliza clones en ../../repos (o similar) y añádelo al .gitignore del AppHost.

Seguridad y CI/CD

  • Tokens solo lectura para clonado en CI, con rotación periódica.
  • Loguea el commit efectivo clonado para auditoría y trazabilidad.

Composición Aspire

  • Modela la topología con WithReference(...) y define puertos con WithHttpEndpoint(...).
  • Elige nombres de recursos claros: los verás en logs y en el Dashboard.

DevEx

  • Acompaña el AppHost con un Dev Container (toolchains .NET/Node + credenciales Git de lectura).
  • Conectividad: el clonado ocurre al ejecutar el AppHost; sin acceso a Git/credenciales, fallará la proyección.
  • Reproducibilidad: si necesitas pin por commit/tag, añade un pre-paso que mueva la rama al commit aprobado y déjalo en logs.
  • Toolchains: si proyectas apps JavaScript, asegúrate de tener Node/npm tanto en local como en CI.

Equipo A mantiene orders-api (.NET) y Equipo B mantiene portal (React) en repos separados. En un AppHost de plataforma:

  • Declaras orders-api desde su repo y lo expones en http://localhost:5180.
  • Declaras portal con AddNpmAppFromRepository(...).WithHttpEndpoint(3000) y lo cableas a orders-api con WithReference.
  • QA y Dev levantan todo con dotnet run y ven la topología en el Aspire Dashboard sin scripts ad-hoc.


Del caos multi-repo al orden operable: con .NET Aspire + Aspire.PolyRepo pasas de scripts y manualidades a configuración declarativa, orquestación consistente y una experiencia de desarrollo mucho más fluida—local y en CI/CD.

Tagged in :

Avatar de David Oliva

Deja una respuesta

Otras lecturas que no te puedes perder