Skip to content

Add Lume docs site migration #6335

Add Lume docs site migration

Add Lume docs site migration #6335

Workflow file for this run

name: Build
on:
workflow_dispatch:
repository_dispatch:
types: [preview]
push:
branches: [main]
tags: ["v*"]
pull_request:
permissions:
contents: read
issues: write
packages: write
pull-requests: write
env:
DOTNET_NOLOGO: true
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
jobs:
preview-context:
if: ${{ (github.event_name == 'repository_dispatch' && github.event.action == 'preview') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'dev-preview')) }}
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
pr-number: ${{ steps.pr.outputs.pr-number }}
pr-sha: ${{ steps.pr.outputs.pr-sha }}
pr-short-sha: ${{ steps.pr.outputs.pr-short-sha }}
branch: ${{ steps.pr.outputs.branch }}
steps:
- name: Resolve preview pull request
id: pr
uses: actions/github-script@v8
with:
script: |
if (context.eventName === "repository_dispatch") {
const payload = context.payload.client_payload ?? {};
const prNumber = Number(payload.pr_number);
const headSha = payload.head_sha;
if (!prNumber || !headSha) {
core.setFailed("Preview dispatch payload is missing pr_number or head_sha.");
return;
}
core.setOutput("pr-number", String(prNumber));
core.setOutput("pr-sha", headSha);
core.setOutput("pr-short-sha", headSha.slice(0, 12));
core.setOutput("branch", payload.head_label || payload.head_ref || "unknown");
return;
}
const pullRequest = context.payload.pull_request;
core.setOutput("pr-number", String(pullRequest.number));
core.setOutput("pr-sha", pullRequest.head.sha);
core.setOutput("pr-short-sha", pullRequest.head.sha.slice(0, 12));
core.setOutput("branch", pullRequest.head.label || pullRequest.head.ref);
preview-comment-running:
needs: [preview-context]
if: ${{ always() && needs.preview-context.outputs.pr-number != '' }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Post sticky running comment
uses: marocchino/sticky-pull-request-comment@v3
with:
number: ${{ needs.preview-context.outputs.pr-number }}
header: exceptionless-preview
message: |
Preview deploy running - [view progress](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
Building images and deploying the shared dev environment. This comment will update with the dev URL when the deploy finishes.
- Branch: `${{ needs.preview-context.outputs.branch }}`
- Commit: [`${{ needs.preview-context.outputs.pr-short-sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ needs.preview-context.outputs.pr-sha }})
version:
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
version: ${{ steps.version.outputs.version }}
should_publish: ${{ (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'dev-preview')) && secrets.DOCKER_USERNAME != '' && secrets.DOCKER_PASSWORD != '' }}
is_prod_deploy: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name != 'pull_request' }}
is_dev_deploy: ${{ (github.event_name == 'repository_dispatch' && github.event.action == 'preview') || (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'dev-preview')) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}
- name: Build Reason
env:
GITHUB_EVENT: ${{ toJson(github) }}
PREVIEW_HEAD_REF: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_ref) || '' }}
run: |
branch=${PREVIEW_HEAD_REF:-${GITHUB_HEAD_REF:-${GITHUB_REF##*/}}}
branch=${branch//\//.}.
if [[ "$branch" = "main." || "$branch" = "master." || "${GITHUB_REF}" = refs/tags* ]]; then
branch=""
fi
echo "GIT_BRANCH_SUFFIX=$branch" >> $GITHUB_ENV
echo "ref: $GITHUB_REF event: $GITHUB_EVENT_NAME branch_suffix: $branch"
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.301
- name: Version
id: version
run: |
dotnet tool install --global minver-cli --version 7.0.0
version=$(minver --tag-prefix v --default-pre-release-identifiers "preview.${GIT_BRANCH_SUFFIX}0")
# If on a non-main branch, insert branch name before the height (last numeric segment)
if [ -n "$GIT_BRANCH_SUFFIX" ]; then
branch_name="${GIT_BRANCH_SUFFIX%.}"
if [[ "$version" != *"$branch_name"* ]]; then
version=$(echo "$version" | sed -E "s/\.([0-9]+)$/.${GIT_BRANCH_SUFFIX}\1/")
fi
fi
echo "version=$version" >> $GITHUB_OUTPUT
echo "### $version" >> $GITHUB_STEP_SUMMARY
test-api:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.301
- uses: actions/cache@v5
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
nuget-${{ runner.os }}-
- name: Nuget Restore
run: dotnet restore ./Exceptionless.slnx
- name: Build
run: dotnet build ./Exceptionless.slnx --no-restore --configuration Release
- name: Run .NET Tests with Coverage
run: dotnet test --no-restore --no-build --configuration Release --results-directory coverage --max-parallel-test-modules 1 -- --report-github --report-xunit-trx --report-xunit-trx-filename test-results.trx --coverage --coverage-settings ${{ github.workspace }}/tests/CodeCoverage.config --coverage-output coverage.cobertura.xml --coverage-output-format cobertura
- name: Code Coverage Summary Report
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: coverage/coverage.cobertura.xml
badge: true
format: "markdown"
output: "both"
- name: Add Coverage PR Comment
uses: marocchino/sticky-pull-request-comment@v3
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md
- name: Write Coverage to Job Summary
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
test-client:
runs-on: ubuntu-latest
timeout-minutes: 30
defaults:
run:
working-directory: src/Exceptionless.Web/ClientApp
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}
- name: Setup Node.js environment
uses: actions/setup-node@v6
with:
node-version: 24
- name: Cache node_modules
uses: actions/cache@v5
id: cache-node-modules
with:
path: src/Exceptionless.Web/ClientApp/node_modules
key: node-modules-${{ hashFiles('src/Exceptionless.Web/ClientApp/package-lock.json') }}
- name: Install Npm Packages
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- name: Lint Client
run: npm run lint
- name: Check
run: npm run check
- name: Build
run: npm run build
- name: Run Unit Tests
run: echo "npm run test:unit"
- name: Run Integration Tests
run: echo "npm run test:integration"
docker-build:
runs-on: ubuntu-latest
needs: [version]
timeout-minutes: 30
env:
VERSION: ${{ needs.version.outputs.version }}
STAGING_TAG: build-${{ github.run_id }}-${{ github.run_attempt }}
SHOULD_PUBLISH: ${{ needs.version.outputs.should_publish }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
platforms: linux/amd64
- name: Login to GitHub Container Registry
if: ${{ env.SHOULD_PUBLISH == 'true' }}
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build api docker image
run: |
echo "::remove-matcher owner=csc::"
if [ "$SHOULD_PUBLISH" = "true" ]; then
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target api --platform linux/amd64 --tag ghcr.io/exceptionless/exceptionless/api-ci:$STAGING_TAG --cache-from type=registry,ref=ghcr.io/exceptionless/exceptionless/api-ci:buildcache --cache-to type=registry,ref=ghcr.io/exceptionless/exceptionless/api-ci:buildcache,mode=max --push
else
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target api --platform linux/amd64 --tag exceptionless/api-ci:latest --cache-from type=gha,scope=api-ci --cache-to type=gha,scope=api-ci,mode=max --load
fi
- name: Build job docker image
run: |
echo "::remove-matcher owner=csc::"
if [ "$SHOULD_PUBLISH" = "true" ]; then
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target job --platform linux/amd64 --tag ghcr.io/exceptionless/exceptionless/job-ci:$STAGING_TAG --cache-from type=registry,ref=ghcr.io/exceptionless/exceptionless/job-ci:buildcache --cache-to type=registry,ref=ghcr.io/exceptionless/exceptionless/job-ci:buildcache,mode=max --push
else
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target job --platform linux/amd64 --tag exceptionless/job-ci:latest --cache-from type=gha,scope=job-ci --cache-to type=gha,scope=job-ci,mode=max --load
fi
- name: Build app docker image
run: |
echo "::remove-matcher owner=csc::"
if [ "$SHOULD_PUBLISH" = "true" ]; then
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target app --platform linux/amd64 --tag ghcr.io/exceptionless/exceptionless/app-ci:$STAGING_TAG --cache-from type=registry,ref=ghcr.io/exceptionless/exceptionless/app-ci:buildcache --cache-to type=registry,ref=ghcr.io/exceptionless/exceptionless/app-ci:buildcache,mode=max --push
else
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target app --platform linux/amd64 --tag exceptionless/app-ci:latest --cache-from type=gha,scope=app-ci --cache-to type=gha,scope=app-ci,mode=max --load
fi
- name: Build all-in-one docker image
if: ${{ needs.version.outputs.is_prod_deploy == 'true' }}
run: |
echo "::remove-matcher owner=csc::"
if [ "$SHOULD_PUBLISH" = "true" ]; then
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target exceptionless --platform linux/amd64 --tag ghcr.io/exceptionless/exceptionless/exceptionless-ci:$STAGING_TAG --cache-from type=registry,ref=ghcr.io/exceptionless/exceptionless/exceptionless-ci:buildcache --cache-to type=registry,ref=ghcr.io/exceptionless/exceptionless/exceptionless-ci:buildcache,mode=max --push
else
docker buildx build . --build-arg MinVerVersionOverride=$VERSION --target exceptionless --platform linux/amd64 --tag exceptionless/exceptionless-ci:latest --cache-from type=gha,scope=exceptionless-ci --cache-to type=gha,scope=exceptionless-ci,mode=max --load
fi
docker-publish:
if: ${{ needs.version.outputs.should_publish == 'true' }}
runs-on: ubuntu-latest
needs: [version, docker-build, test-api, test-client]
timeout-minutes: 30
env:
VERSION: ${{ needs.version.outputs.version }}
STAGING_TAG: build-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@v4
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Pull staged docker images
run: |
images=(api job app)
if [ "${{ needs.version.outputs.is_prod_deploy }}" = "true" ]; then
images+=(exceptionless)
fi
for image in "${images[@]}"; do
docker pull ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG
done
- name: Publish CI Packages
run: |
echo "::remove-matcher owner=csc::"
# tag and push docker images
images=(api job app)
if [ "${{ needs.version.outputs.is_prod_deploy }}" = "true" ]; then
images+=(exceptionless)
fi
for image in "${images[@]}"; do
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG exceptionless/$image-ci:$VERSION
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG exceptionless/$image-ci:latest
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG ghcr.io/exceptionless/exceptionless/$image-ci:$VERSION
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG ghcr.io/exceptionless/exceptionless/$image-ci:latest
docker image push --all-tags exceptionless/$image-ci
docker image push --all-tags ghcr.io/exceptionless/exceptionless/$image-ci
done
- name: Publish Release Packages
if: ${{ needs.version.outputs.is_prod_deploy == 'true' }}
run: |
echo "::remove-matcher owner=csc::"
# tag and push docker images
images=(api job app exceptionless)
for image in "${images[@]}"; do
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG exceptionless/$image:$VERSION
docker image tag ghcr.io/exceptionless/exceptionless/$image-ci:$STAGING_TAG exceptionless/$image:latest
docker image push --all-tags exceptionless/$image
done
- name: Summary
if: ${{ always() }}
run: |
echo "### Build Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: $VERSION" >> $GITHUB_STEP_SUMMARY
echo "- **CI Images**: Published ✅" >> $GITHUB_STEP_SUMMARY
echo "- **Release Images**: ${{ needs.version.outputs.is_prod_deploy == 'true' && 'Published ✅' || 'Skipped' }}" >> $GITHUB_STEP_SUMMARY
echo "- **Deploy**: ${{ needs.version.outputs.is_dev_deploy == 'true' && 'Development queued' || (needs.version.outputs.is_prod_deploy == 'true' && 'Production queued' || 'Skipped') }}" >> $GITHUB_STEP_SUMMARY
deploy:
if: ${{ needs.version.outputs.should_publish == 'true' }}
needs: [version, docker-publish]
runs-on: ubuntu-latest
timeout-minutes: 30
concurrency:
group: ${{ needs.version.outputs.is_dev_deploy == 'true' && 'dev-environment-deploy' || format('deploy-{0}', github.run_id) }}
cancel-in-progress: false
env:
VERSION: ${{ needs.version.outputs.version }}
CLUSTER_NAME: ex-k8s-v6
RESOURCE_GROUP: exceptionless-v6
DEV_NAMESPACE: ex-dev
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }}
- name: Install Helm
uses: azure/setup-helm@v5
- name: Azure Login
if: ${{ needs.version.outputs.is_dev_deploy == 'true' || needs.version.outputs.is_prod_deploy == 'true' }}
run: az login --service-principal --username ${{ secrets.AZ_USERNAME }} --password ${{ secrets.AZ_PASSWORD }} --tenant ${{ secrets.AZ_TENANT }} --output none
- name: Get AKS Credentials
if: ${{ needs.version.outputs.is_dev_deploy == 'true' || needs.version.outputs.is_prod_deploy == 'true' }}
run: az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --overwrite-existing
- name: Ensure Development Infrastructure is Running
if: ${{ needs.version.outputs.is_dev_deploy == 'true' }}
run: |
kubectl scale statefulset/ex-dev-es-main --replicas=1 --namespace $DEV_NAMESPACE
kubectl apply -f k8s/ex-dev-redis.yaml
kubectl wait --for=condition=ready --timeout=300s pod ex-dev-es-main-0 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-kb --replicas=1 --namespace $DEV_NAMESPACE
- name: Deploy Changes to Development Environment
if: ${{ needs.version.outputs.is_dev_deploy == 'true' }}
run: |
sed -i "s/^appVersion:.*$/appVersion: '${VERSION}'/" ./k8s/exceptionless/Chart.yaml
helm upgrade --set "version=${VERSION}" --reuse-values --values ./k8s/ex-dev-values.yaml ex-dev --namespace $DEV_NAMESPACE ./k8s/exceptionless
- name: Ensure Development Workloads are Running
if: ${{ needs.version.outputs.is_dev_deploy == 'true' }}
run: |
kubectl scale deployment/ex-dev-app --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-api --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-close-inactive-sessions --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-daily-summary --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-event-notifications --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-event-usage --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-event-posts --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-event-user-descriptions --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-mail-message --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-stack-event-count --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-web-hooks --replicas=1 --namespace $DEV_NAMESPACE
kubectl scale deployment/ex-dev-jobs-work-item --replicas=1 --namespace $DEV_NAMESPACE
kubectl patch cronjob/ex-dev-jobs-cleanup-data -p '{"spec":{"suspend": false}}' --namespace $DEV_NAMESPACE
kubectl patch cronjob/ex-dev-jobs-cleanup-orphaned-data -p '{"spec":{"suspend": false}}' --namespace $DEV_NAMESPACE
kubectl patch cronjob/ex-dev-jobs-download-geoip-database -p '{"spec":{"suspend": false}}' --namespace $DEV_NAMESPACE
kubectl patch cronjob/ex-dev-jobs-maintain-indexes -p '{"spec":{"suspend": false}}' --namespace $DEV_NAMESPACE
kubectl patch cronjob/ex-dev-jobs-migration -p '{"spec":{"suspend": false}}' --namespace $DEV_NAMESPACE
kubectl wait --for=condition=available --timeout=300s deployment/ex-dev-app --namespace $DEV_NAMESPACE
kubectl wait --for=condition=available --timeout=300s deployment/ex-dev-api --namespace $DEV_NAMESPACE
kubectl annotate namespace $DEV_NAMESPACE exceptionless.io/dev-started-at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" --overwrite
kubectl annotate namespace $DEV_NAMESPACE exceptionless.io/dev-auto-stop-days="1" --overwrite
kubectl annotate namespace $DEV_NAMESPACE exceptionless.io/dev-auto-stop-hours- --overwrite 2>/dev/null || true
- name: Deploy Changes to Production Environment
if: ${{ needs.version.outputs.is_prod_deploy == 'true' }}
run: |
sed -i "s/^appVersion:.*$/appVersion: '${VERSION}'/" ./k8s/exceptionless/Chart.yaml
helm upgrade --set "version=${VERSION}" --reuse-values --values ./k8s/ex-prod-values.yaml ex-prod --namespace ex-prod ./k8s/exceptionless
- name: Summary
if: ${{ always() }}
run: |
echo "### Deployment Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: $VERSION" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.version.outputs.is_dev_deploy }}" = "true" ]; then
echo "- **Environment**: Development" >> $GITHUB_STEP_SUMMARY
echo "- **App**: https://dev-app.exceptionless.io" >> $GITHUB_STEP_SUMMARY
echo "- **Collector**: https://dev-collector.exceptionless.io" >> $GITHUB_STEP_SUMMARY
elif [ "${{ needs.version.outputs.is_prod_deploy }}" = "true" ]; then
echo "- **Environment**: Production" >> $GITHUB_STEP_SUMMARY
echo "- **App**: https://be.exceptionless.io" >> $GITHUB_STEP_SUMMARY
echo "- **Collector**: https://collector.exceptionless.io" >> $GITHUB_STEP_SUMMARY
else
echo "- **Deployment**: Skipped" >> $GITHUB_STEP_SUMMARY
fi
preview-comment-result:
needs: [preview-context, version, test-api, test-client, docker-build, docker-publish, deploy]
if: ${{ always() && needs.preview-context.outputs.pr-number != '' }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Post sticky deployed comment
if: ${{ needs.deploy.result == 'success' }}
uses: marocchino/sticky-pull-request-comment@v3
with:
number: ${{ needs.preview-context.outputs.pr-number }}
header: exceptionless-preview
message: |
Preview deployed
- **App:** https://dev-app.exceptionless.io
- **Collector:** https://dev-collector.exceptionless.io
- Commit: [`${{ needs.preview-context.outputs.pr-short-sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ needs.preview-context.outputs.pr-sha }})
- Version: `${{ needs.version.outputs.version }}`
- Workflow run: [view logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
- name: Post sticky failed comment
if: ${{ needs.deploy.result != 'success' }}
uses: marocchino/sticky-pull-request-comment@v3
with:
number: ${{ needs.preview-context.outputs.pr-number }}
header: exceptionless-preview
message: |
Preview deploy failed or did not complete. See [run logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
- Branch: `${{ needs.preview-context.outputs.branch }}`
- Commit: [`${{ needs.preview-context.outputs.pr-short-sha }}`](${{ github.server_url }}/${{ github.repository }}/commit/${{ needs.preview-context.outputs.pr-sha }})
- Version: `${{ needs.version.outputs.version || 'not computed' }}`