Skip to content

docs: tighten README + onboarding for chained Ensure-All-Indexes #249

docs: tighten README + onboarding for chained Ensure-All-Indexes

docs: tighten README + onboarding for chained Ensure-All-Indexes #249

Workflow file for this run

name: Build & Publish
on:
push:
branches: [main]
paths-ignore:
- "**.md"
- "eng/**"
- ".claude/**"
- ".agents/**"
- ".editorconfig"
- "NOTES.md"
- "LICENSE"
workflow_dispatch:
permissions:
contents: write
packages: write
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for GitVersion
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v3
with:
versionSpec: "6.x"
- name: Calculate version
id: version
uses: gittools/actions/gitversion/execute@v3
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Install Aspire CLI
run: |
curl -sSL https://aspire.dev/install.sh | bash
echo "$HOME/.aspire/bin" >> $GITHUB_PATH
- name: Build solution
run: |
dotnet build src/StarWarsData.slnx -c Release \
/p:Version=${{ steps.version.outputs.semVer }} \
/p:AssemblyVersion=${{ steps.version.outputs.assemblySemVer }} \
/p:FileVersion=${{ steps.version.outputs.assemblySemFileVer }} \
/p:InformationalVersion=${{ steps.version.outputs.informationalVersion }}
- name: Run tests
run: dotnet test --project src/StarWarsData.Tests -c Release --no-build --filter 'TestCategory=Unit'
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push container images (versioned)
run: aspire do push --apphost src/StarWarsData.AppHost/StarWarsData.AppHost.csproj
env:
CONTAINER_IMAGE_TAG: ${{ steps.version.outputs.semVer }}
- name: Build and push container images (latest)
run: aspire do push --apphost src/StarWarsData.AppHost/StarWarsData.AppHost.csproj
env:
CONTAINER_IMAGE_TAG: latest
# `aspire publish` emits docker-compose.yaml + an UNFILLED .env.Production template
# (just placeholder keys, no values). Secrets stay out of the runner environment
# entirely. The deploy host is responsible for materializing real values from its
# own secret store before `docker compose --env-file .env.Production up -d`.
# See eng/design/017-aspire-publish-deploy-workflow.md for the full contract.
- name: Publish deployment artifacts (template only, no secrets)
run: |
aspire publish \
-e Production \
--apphost src/StarWarsData.AppHost/StarWarsData.AppHost.csproj \
--non-interactive \
--output-path ./aspire-output
env:
CONTAINER_IMAGE_TAG: ${{ steps.version.outputs.semVer }}
# Defense in depth: fail loudly if anything in the output looks like a real OpenAI
# key or a non-empty Mongo credential, in case Aspire's `publish` contract changes
# in a future release. We'd rather break the build than ship a leaked artifact.
- name: Verify artifact contains no secrets
run: |
set -euo pipefail
if grep -REn 'sk-[A-Za-z0-9_-]{20,}' ./aspire-output/; then
echo "::error::aspire-output appears to contain an OpenAI key — refusing to upload."
exit 1
fi
if grep -REn '^Parameters__mongo_password=.+' ./aspire-output/; then
echo "::error::aspire-output appears to contain a populated mongo_password — refusing to upload."
exit 1
fi
- name: Upload deployment artifacts
uses: actions/upload-artifact@v4
with:
name: release
path: ./aspire-output/
retention-days: 30
include-hidden-files: true
- name: Tag release
run: |
git tag "v${{ steps.version.outputs.semVer }}"
git push origin "v${{ steps.version.outputs.semVer }}"