# SAIF .NET Core Framework — NuGet Pipelines (Mono-repo)

## Overview

Every component under `src/` in this repository is packaged and published to NuGet by its **own independent Azure DevOps YAML pipeline** — moving to a mono-repo did not change the one-pipeline-per-package model. All pipelines live in the **`Architecture`** project of the `SAIFCorporation` organization and are triggered from this single repository (`Framework.NCore`), scoped so that a change to one component only queues that component's pipeline.

These 19 pipelines are the same production pipeline **definitions** that previously built from the 19 standalone `Framework.NCore.<Component>` repositories (same definition IDs, same names, same build history) — they were **retargeted** in place to this repository rather than recreated, so existing build history/badges/links are preserved. Each standalone repo's pipeline(s) have since been disabled.

All pipelines share a common shape:

- The pipeline YAML lives at `.azdo/{component}/azure-pipelines.yml` and pulls in shared templates from `SAIF/yaml_templates_v3` via the `templates` repository resource:
  - `/templates/shared/variables/vars.yml@templates` — org-wide variables.
  - `/templates/app-types/nuget/variables/vars.yml@templates` — NuGet-app-type variables.
  - `/templates/app-types/nuget/stages/build-deploy-standard.yml@templates` — the multi-stage build/pack/push logic (restore → build → test → `dotnet pack` → push to the NuGet feed).
  - `.azdo/{component}/variables/vars.yml` supplies per-component parameters (`appName`, `appOwner`, `dotnetType`, `releaseBranch: main`, `vstsFeed: saifnuget`, `feedPublish: SAIFNuget`, `solutionPath`, `projectFile`) — `solutionPath`/`projectFile` now point into `src/{component}/...` to reflect the mono-repo layout.
- **CI trigger is scoped per component**: batched pushes to `main` under `src/{component}/**` only (`trigger.batch: true`, `branches.include: [main]`, `paths.include: [src/{component}/**]`). A change to `src/SAIF.NetCore.AuthService/**` only queues the AuthService pipeline, not the other 18.
- The build pool is parameterized via `$(SAIF.BuildPool)`, which resolves to the Microsoft-hosted **`Azure Pipelines`** pool.
- Package version numbers follow `<MajorVersion>.<Year>.<DayOfYear>.<rev>` (e.g. `8.2026.26266.1`).

## Current pipeline definitions

| Component (`src/...`) | Pipeline name (definition ID) | Published package | YAML path | Trigger / pool |
|---|---|---|---|---|
| SAIF.NetCore.AuthService | [`Framework.NCore.AuthService.nuget.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5212) (5212) | SAIF.NetCore.AuthService | `.azdo/SAIF.NetCore.AuthService/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.AuthService/**`), pool `Azure Pipelines` |
| SAIF.NetCore.Common | [`Framework.NCore.Common.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5213) (5213) | SAIF.NetCore.Common | `.azdo/SAIF.NetCore.Common/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.Common/**`), pool `Azure Pipelines` |
| SAIF.NetCore.DbConnectionClient | [`Framework.NCore.DBConnectionClient.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5214) (5214) | SAIF.NetCore.DbConnectionClient | `.azdo/SAIF.NetCore.DbConnectionClient/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.DbConnectionClient/**`), pool `Azure Pipelines` |
| SAIF.NetCore.EnvironmentClient | [`Framework.NCore.EnvironmentClient.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5215) (5215) | SAIF.NetCore.EnvironmentClient | `.azdo/SAIF.NetCore.EnvironmentClient/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.EnvironmentClient/**`), pool `Azure Pipelines` |
| SAIF.NetCore.ErrorHandler | [`Framework.NCore.ErrorHandler.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5216) (5216) | SAIF.NetCore.ErrorHandler | `.azdo/SAIF.NetCore.ErrorHandler/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.ErrorHandler/**`), pool `Azure Pipelines` |
| SAIF.NetCore.HashUtil | [`Framework.NCore.HashUtil.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5217) (5217) | SAIF.NetCore.HashUtil | `.azdo/SAIF.NetCore.HashUtil/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.HashUtil/**`), pool `Azure Pipelines` |
| SAIF.NetCore.HttpClients | [`Framework.NCore.HttpClients.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5218) (5218) | SAIF.NetCore.HttpClients | `.azdo/SAIF.NetCore.HttpClients/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.HttpClients/**`), pool `Azure Pipelines` |
| SAIF.NetCore.LegacyAuth | [`Framework.NCore.LegacyAuth.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5219) (5219) | SAIF.NetCore.LegacyAuth | `.azdo/SAIF.NetCore.LegacyAuth/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.LegacyAuth/**`), pool `Azure Pipelines` |
| Messaging | [`SAIF.NetCore.Services.Messaging.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5220) (5220) | SAIF.NetCore.Services.Messaging | `.azdo/Messaging/azure-pipelines.yml` | CI on `main` (`src/Messaging/**`), pool `Azure Pipelines` |
| SAIF.NetCore.Nhibernate | [`Framework.NCore.NHibernate.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5221) (5221) | SAIF.NetCore.Nhibernate | `.azdo/SAIF.NetCore.Nhibernate/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.Nhibernate/**`), pool `Azure Pipelines` |
| SAIF.NetCore.NtlmApiAuth | [`Framework.NCore.NtlmApiAuth.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5222) (5222) | SAIF.NetCore.NtlmApiAuth | `.azdo/SAIF.NetCore.NtlmApiAuth/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.NtlmApiAuth/**`), pool `Azure Pipelines` |
| SAIF.NetCore.OIDC | [`Framework.NCore.OIDC.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5223) (5223) | SAIF.NetCore.OIDC | `.azdo/SAIF.NetCore.OIDC/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.OIDC/**`), pool `Azure Pipelines` |
| SAIF.NetCore.PingableService | [`Framework.NCore.PingableService.nuget.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5224) (5224) | SAIF.NetCore.PingableService | `.azdo/SAIF.NetCore.PingableService/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.PingableService/**`), pool `Azure Pipelines` |
| SAIF.NetCore.Logging | [`Framework.NCore.SaifLog.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5225) (5225) | SAIF.NetCore.Logging | `.azdo/SAIF.NetCore.Logging/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.Logging/**`), pool `Azure Pipelines` |
| SAIF.NetCore.ServiceContracts | [`SAIF.NetCore.ServiceContracts.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5226) (5226) | SAIF.NetCore.ServiceContracts | `.azdo/SAIF.NetCore.ServiceContracts/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.ServiceContracts/**`), pool `Azure Pipelines` |
| SAIF.NetCore.ServiceExtensions | [`Framework.NCore.ServiceExtensions.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5227) (5227) | SAIF.NetCore.ServiceExtensions | `.azdo/SAIF.NetCore.ServiceExtensions/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.ServiceExtensions/**`), pool `Azure Pipelines` |
| SAIF.NetCore.SystemHash | [`Framework.NCore.SystemHash.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5229) (5229) | SAIF.NetCore.SystemHash | `.azdo/SAIF.NetCore.SystemHash/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.SystemHash/**`), pool `Azure Pipelines` |
| SAIF.NetCore.Clients.UC4 | [`Framework.NCore.UC4Client.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5230) (5230) | SAIF.NetCore.Clients.UC4 | `.azdo/SAIF.NetCore.Clients.UC4/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.Clients.UC4/**`), pool `Azure Pipelines` |
| SAIF.NetCore.WindowsService | [`Framework.NCore.WindowsService.nuget.Build.Release`](https://dev.azure.com/SAIFCorporation/Architecture/_build/definition?definitionId=5231) (5231) | SAIF.NetCore.WindowsService | `.azdo/SAIF.NetCore.WindowsService/azure-pipelines.yml` | CI on `main` (`src/SAIF.NetCore.WindowsService/**`), pool `Azure Pipelines` |

All 19 pipelines above are **enabled**, live at path `\` (root) in the `Architecture` project's pipeline list, point their `repository` at this repo (`Framework.NCore`, default branch `refs/heads/main`), and were **verified with a green build against `main` in this repository** as part of the mono-repo migration.

## Migration to the mono-repo

1. All source and `.azdo/{component}` pipeline configuration were copied from the 19 standalone `Framework.NCore.<Component>` repositories into this repository under `src/{component}` and `.azdo/{component}` respectively.
2. Each pipeline YAML's trigger path filter was narrowed from the previous repo-wide `src/**` to a component-scoped `src/{component}/**`, and the `master` branch references were updated to `main`.
3. Each existing pipeline **definition** (same ID, same name, same build history) was retargeted via the Azure DevOps REST API to point its `repository` at `Framework.NCore` (`refs/heads/main`) instead of its old standalone repo — this preserves build history/links rather than creating new pipelines.
4. Every retargeted pipeline was verified with a successful build against this repository's `main` branch.
5. The old standalone repos' pipelines were disabled (including one, `SAIF.NetCore.Services.Messaging` (1781), that had been missed by the earlier classic-pipeline retirement and was still enabled — it has now been disabled and moved to `\Retired` as well). The standalone repositories themselves are left in place, but are no longer built.

## Branch protection on `main`

- **Minimum reviewers: 1** (blocking) — every PR into `main` requires at least one approval.
- **Optional auto-reviewers** (non-blocking, automatically added for awareness/visibility): `Technology Architect`, `Technology Architecture Mgr`, `Site Reliability Engineer II`. (`Site Reliability Engineer III`/`IV` groups do not currently exist in Azure DevOps for this org and were not added — create them and add as reviewers if/when they exist.)

## How to inspect a pipeline yourself

```text
# Get a pipeline definition (includes repository, triggers, queue/pool)
az devops invoke --area build --resource Definitions --route-parameters project=Architecture definitionId=<id> --http-method GET --api-version 7.1

# List builds / get status for a definition
az pipelines build list --definition <id> --project Architecture
az pipelines build show --id <buildId> --project Architecture
```
