Skip to content

build(deps-dev): bump @types/node from 26.4.0 to 26.4.1 in /src/micro… #1052

build(deps-dev): bump @types/node from 26.4.0 to 26.4.1 in /src/micro…

build(deps-dev): bump @types/node from 26.4.0 to 26.4.1 in /src/micro… #1052

name: Build, Test, and Deploy Try .NET API
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
workflow_dispatch:
permissions:
id-token: write
contents: read
jobs:
build-and-test:
runs-on: ubuntu-latest
environment: "BuildAndUploadImage"
permissions:
actions: write # required for docker/build-push-action GHA cache writes
contents: read
steps:
- uses: actions/checkout@v7
- name: Set up Node.js environment
uses: ./.github/actions/setup-node
- name: Set up .NET environment
uses: ./.github/actions/setup-dotnet
- name: Run ciTest for microsoft-trydotnet
working-directory: src/microsoft-trydotnet
run: npm run ciTest
- name: Run ciTest for microsoft-trydotnet-editor
working-directory: src/microsoft-trydotnet-editor
run: npm run ciTest
- name: Run .NET Tests
id: run-dotnet-tests
run: dotnet test --no-build --configuration Release --blame-hang-timeout 15m --blame-hang-dump-type full -l trx --results-directory ./TestResults
env:
POCKETLOGGER_LOG_PATH: ${{ github.workspace }}/artifacts/logs/pocketlogger.log
- name: Convert TRX to Playlist
if: ${{ steps.run-dotnet-tests.outcome == 'failure' || failure() }}
uses: BenjaminMichaelis/trx-to-vsplaylist@v4
with:
trx-file-path: './TestResults/*.trx'
test-outcomes: 'Failed'
artifact-name: 'linux-test-playlists'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
id: setup-buildx
- name: Cache Docker build mounts (main)
if: github.ref == 'refs/heads/main'
uses: actions/cache@v6
id: cache-mounts-main
with:
path: .buildkit-cache
key: buildkit-cache-${{ hashFiles('Dockerfile', 'Directory.Packages.props', 'NuGet.config', 'src/**/package-lock.json') }}
restore-keys: |
buildkit-cache-
- name: Restore Docker build mounts (PR)
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
uses: actions/cache/restore@v6
id: cache-mounts-pr
with:
path: .buildkit-cache
key: buildkit-cache-${{ hashFiles('Dockerfile', 'Directory.Packages.props', 'NuGet.config', 'src/**/package-lock.json') }}
restore-keys: |
buildkit-cache-
- name: Inject Docker cache mounts
uses: reproducible-containers/buildkit-cache-dance@v3
with:
builder: ${{ steps.setup-buildx.outputs.name }}
cache-dir: .buildkit-cache
dockerfile: Dockerfile
skip-extraction: ${{ github.ref != 'refs/heads/main' || steps.cache-mounts-main.outputs.cache-hit == 'true' }}
# Build but no push with a PR
- name: Docker build (no push)
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
uses: docker/build-push-action@v7
with:
push: false
tags: temp-pr-validation
file: ./Dockerfile
cache-from: type=gha,scope=try-main
# Only build for dev registry — prod gets the image via az acr import in deploy-production
- name: Build Container Image
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v7
with:
tags: ${{ vars.DEVCONTAINER_REGISTRY }}/try:${{ github.sha }},${{ vars.DEVCONTAINER_REGISTRY }}/try:latest
file: ./Dockerfile
context: .
outputs: type=docker,dest=${{ github.workspace }}/tryimage.tar
cache-from: type=gha,scope=try-main
cache-to: type=gha,mode=max,scope=try-main
- name: Upload artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v7.0.1
with:
name: tryimage
path: ${{ github.workspace }}/tryimage.tar
build-and-test-windows:
# Ensures .NET build and unit tests pass on Windows, matching the original
# Azure DevOps Windows_NT job. Integration tests are covered separately.
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- name: Set up Node.js environment
uses: ./.github/actions/setup-node
- name: Set up .NET environment
uses: ./.github/actions/setup-dotnet
- name: Run .NET Tests
id: run-dotnet-tests
run: dotnet test --no-build --configuration Release --blame-hang-timeout 15m --blame-hang-dump-type full -l trx --results-directory ./TestResults
env:
POCKETLOGGER_LOG_PATH: ${{ github.workspace }}/artifacts/logs/pocketlogger.log
- name: Convert TRX to Playlist
if: ${{ steps.run-dotnet-tests.outcome == 'failure' || failure() }}
uses: BenjaminMichaelis/trx-to-vsplaylist@v4
with:
trx-file-path: './TestResults/*.trx'
test-outcomes: 'Failed'
artifact-name: 'windows-test-playlists'
integration-tests:
# Integration tests use Playwright and are gated behind RunIntegrationTests=true.
# IntegrationTestFactAttribute explicitly skips these tests on Linux, so a
# Windows runner is required to actually execute them.
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- name: Set up Node.js environment
uses: ./.github/actions/setup-node
- name: Set up .NET environment
uses: ./.github/actions/setup-dotnet
- name: Run .NET Integration Tests
id: run-dotnet-integration-tests
run: dotnet test --no-build --configuration Release --blame-hang-timeout 15m --blame-hang-dump-type full -l trx --results-directory ./TestResults
env:
RunIntegrationTests: true
POCKETLOGGER_LOG_PATH: ${{ github.workspace }}/artifacts/logs/pocketlogger.log
TRYDOTNET_PREBUILDS_PATH: ${{ github.workspace }}/artifacts/trydotnet-prebuilds
- name: Convert TRX to Playlist
if: ${{ steps.run-dotnet-integration-tests.outcome == 'failure' || failure() }}
uses: BenjaminMichaelis/trx-to-vsplaylist@v4
with:
trx-file-path: './TestResults/*.trx'
test-outcomes: 'Failed'
artifact-name: 'integration-test-playlists'
deploy-development:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
needs: [build-and-test, build-and-test-windows, integration-tests]
concurrency:
group: deploy-development-try
cancel-in-progress: false
environment:
name: "Development"
permissions:
id-token: write
contents: read
steps:
- name: Azure Login
uses: azure/login@v3
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Download artifact
uses: actions/download-artifact@v8.0.1
with:
name: tryimage
path: ${{ github.workspace }}
- name: Load image
run: |
docker load --input ${{ github.workspace }}/tryimage.tar
docker image ls -a
- name: Log in to container registry
run: |
REGISTRY="${{ vars.DEVCONTAINER_REGISTRY }}"
az acr login --name "${REGISTRY%.azurecr.io}"
- name: Push Image to Dev Container Registry
run: docker push --all-tags ${{ vars.DEVCONTAINER_REGISTRY }}/try
- name: Deploy to Container App
env:
CONTAINER_APP_NAME: ${{ vars.CONTAINER_APP_NAME }}
RESOURCEGROUP: ${{ vars.RESOURCEGROUP }}
run: |
az extension add --name containerapp --upgrade --only-show-errors
az containerapp update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RESOURCEGROUP" \
--image "${{ vars.DEVCONTAINER_REGISTRY }}/try:${{ github.sha }}"
deploy-production:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
needs: deploy-development
concurrency:
group: deploy-production-try
cancel-in-progress: false
environment:
name: "Production"
permissions:
id-token: write
contents: write # needed for git deploy tag
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Azure Login
uses: azure/login@v3
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Server-side copy from dev ACR to prod ACR — no artifact download needed.
# PREREQUISITE: prod OIDC identity must have AcrPull on the dev ACR (Terraform RBAC).
- name: Import image from dev ACR to prod ACR
id: import
run: |
DEV_ACR="${{ vars.DEVCONTAINER_REGISTRY }}"
PROD_ACR="${{ vars.PRODCONTAINER_REGISTRY }}"
az acr import \
--name "${PROD_ACR%.azurecr.io}" \
--source "${DEV_ACR}/try:${{ github.sha }}" \
--image "try:${{ github.sha }}" \
--image "try:latest" \
--force
DIGEST=$(az acr repository show \
--name "${PROD_ACR%.azurecr.io}" \
--image "try:${{ github.sha }}" \
--query "digest" -o tsv)
if [ -z "$DIGEST" ]; then
echo "::error::Failed to capture image digest from prod ACR after import"
exit 1
fi
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Deploy to Container App
env:
CONTAINER_APP_NAME: ${{ vars.CONTAINER_APP_NAME }}
RESOURCEGROUP: ${{ vars.RESOURCEGROUP }}
run: |
az extension add --name containerapp --upgrade --only-show-errors
az containerapp update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RESOURCEGROUP" \
--image "${{ vars.PRODCONTAINER_REGISTRY }}/try@${{ steps.import.outputs.digest }}"
- name: Verify deployed image
env:
CONTAINER_APP_NAME: ${{ vars.CONTAINER_APP_NAME }}
RESOURCEGROUP: ${{ vars.RESOURCEGROUP }}
run: |
DEPLOYED=$(az containerapp show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RESOURCEGROUP" \
--query "properties.template.containers[0].image" -o tsv)
EXPECTED="${{ vars.PRODCONTAINER_REGISTRY }}/try@${{ steps.import.outputs.digest }}"
if [ "$DEPLOYED" != "$EXPECTED" ]; then
echo "::error::Image mismatch! Expected $EXPECTED but found $DEPLOYED"
exit 1
fi
echo "Deployed image verified: $DEPLOYED"
- name: Smoke test
env:
CONTAINER_APP_NAME: ${{ vars.CONTAINER_APP_NAME }}
RESOURCEGROUP: ${{ vars.RESOURCEGROUP }}
run: |
FQDN=$(az containerapp show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RESOURCEGROUP" \
--query "properties.configuration.ingress.fqdn" -o tsv)
# --retry-all-errors ensures HTTP 5xx (cold-start 503s) also trigger retries
curl --fail --retry 10 --retry-delay 15 --retry-all-errors --max-time 30 "https://$FQDN/"
- name: Tag commit as deployed
run: |
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
# -f allows re-tagging the same SHA on workflow re-runs
git tag -f "deployed/prod/${{ github.sha }}"
git push origin "deployed/prod/${{ github.sha }}" --force
- name: Logout of Azure CLI
if: always()
uses: azure/CLI@v3
with:
inlineScript: |
az logout
az cache purge
az account clear