Add Blazor Web App example #27
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy WebApps (All frameworks) | |
| on: | |
| pull_request: | |
| paths: | |
| - "examples/Web Applications/Framework Examples/**" | |
| - ".github/workflows/webapp-deploy.yml" | |
| push: | |
| branches: | |
| - "**" | |
| paths: | |
| - "examples/Web Applications/Framework Examples/**" | |
| - ".github/workflows/webapp-deploy.yml" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| generate-node-matrix: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| is-empty: ${{ steps.set-matrix.outputs.is-empty }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Generate Node apps matrix | |
| id: set-matrix | |
| run: | | |
| BASE_DIR="examples/Web Applications/Framework Examples" | |
| APPS=() | |
| for framework_dir in "$BASE_DIR"/*; do | |
| if [ -d "$framework_dir" ]; then | |
| FRAMEWORK="$(basename "$framework_dir")" | |
| if [[ "$FRAMEWORK" == "Blazor" ]]; then | |
| continue | |
| fi | |
| for app_dir in "$framework_dir"/*; do | |
| if [ -d "$app_dir" ]; then | |
| APPS+=("$FRAMEWORK/$(basename "$app_dir")") | |
| fi | |
| done | |
| fi | |
| done | |
| if [ ${#APPS[@]} -eq 0 ]; then | |
| MATRIX_JSON="[]" | |
| else | |
| MATRIX_JSON=$(printf '%s\n' "${APPS[@]}" | jq -R . | jq -cs .) | |
| fi | |
| echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT" | |
| echo "Generated Node matrix: $MATRIX_JSON" | |
| if [[ "$MATRIX_JSON" == "[]" ]]; then | |
| echo "is-empty=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is-empty=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| generate-blazor-matrix: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| is-empty: ${{ steps.set-matrix.outputs.is-empty }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Generate Blazor apps matrix | |
| id: set-matrix | |
| run: | | |
| BASE_DIR="examples/Web Applications/Framework Examples" | |
| APPS=() | |
| for framework_dir in "$BASE_DIR"/*; do | |
| if [ -d "$framework_dir" ]; then | |
| FRAMEWORK="$(basename "$framework_dir")" | |
| if [[ "$FRAMEWORK" != "Blazor" ]]; then | |
| continue | |
| fi | |
| for app_dir in "$framework_dir"/*; do | |
| if [ -d "$app_dir" ]; then | |
| APPS+=("$FRAMEWORK/$(basename "$app_dir")") | |
| fi | |
| done | |
| fi | |
| done | |
| if [ ${#APPS[@]} -eq 0 ]; then | |
| MATRIX_JSON="[]" | |
| else | |
| MATRIX_JSON=$(printf '%s\n' "${APPS[@]}" | jq -R . | jq -cs .) | |
| fi | |
| echo "matrix=$MATRIX_JSON" >> "$GITHUB_OUTPUT" | |
| echo "Generated Blazor matrix: $MATRIX_JSON" | |
| if [[ "$MATRIX_JSON" == "[]" ]]; then | |
| echo "is-empty=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is-empty=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| build-node: | |
| needs: generate-node-matrix | |
| if: needs.generate-node-matrix.outputs.is-empty != 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app_dir: ${{ fromJSON(needs.generate-node-matrix.outputs.matrix) }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Parse Node app | |
| run: | | |
| APP_DIR="examples/Web Applications/Framework Examples/${{ matrix.app_dir }}" | |
| APP_NAME="$(basename "$APP_DIR")" | |
| echo "APP_DIR=$APP_DIR" >> $GITHUB_ENV | |
| echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.x | |
| - name: Install Node dependencies | |
| working-directory: ${{ env.APP_DIR }} | |
| run: npm ci | |
| - name: Lint Node app | |
| working-directory: ${{ env.APP_DIR }} | |
| run: npm run lint | |
| - name: Build Node app | |
| working-directory: ${{ env.APP_DIR }} | |
| run: npm run build | |
| - name: Prepare Node build folder | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| mkdir -p build | |
| if [ -d dist ]; then mv dist/* build/; fi | |
| - name: Upload Node build artifact | |
| uses: actions/upload-artifact@v6 | |
| if: | |
| github.repository_owner == 'ni' && startsWith(github.ref, | |
| 'refs/heads/main') | |
| with: | |
| name: ${{ env.APP_NAME }}-build | |
| path: ${{ env.APP_DIR }}/build | |
| build-blazor: | |
| needs: generate-blazor-matrix | |
| if: needs.generate-blazor-matrix.outputs.is-empty != 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app_dir: ${{ fromJSON(needs.generate-blazor-matrix.outputs.matrix) }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Parse Blazor app | |
| run: | | |
| APP_DIR="examples/Web Applications/Framework Examples/${{ matrix.app_dir }}" | |
| APP_NAME="$(basename "$APP_DIR")" | |
| echo "APP_DIR=$APP_DIR" >> $GITHUB_ENV | |
| echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v3 | |
| with: | |
| dotnet-version: 10.0 | |
| - name: Restore Blazor dependencies | |
| working-directory: ${{ env.APP_DIR }} | |
| run: dotnet restore | |
| - name: Publish Blazor app | |
| working-directory: ${{ env.APP_DIR }} | |
| run: dotnet publish *.csproj -o dist | |
| - name: Copy fingerprinted dotnet.js | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| MANIFEST=$(find dist -maxdepth 1 -name "*.staticwebassets.endpoints.json" | head -1) | |
| if [ -z "$MANIFEST" ]; then | |
| echo "ERROR: No staticwebassets.endpoints.json found in dist/" | |
| exit 1 | |
| fi | |
| DOTNET_JS=$(grep -o '"Route":"_framework/dotnet\.js","AssetFile":"_framework/[^"]*\.js"' "$MANIFEST" \ | |
| | grep -v '\.js\.br"' | grep -v '\.js\.gz"' | head -1 \ | |
| | sed 's/.*"AssetFile":"_framework\/\(.*\)"/\1/') | |
| if [ -z "$DOTNET_JS" ]; then | |
| echo "ERROR: Could not locate fingerprinted dotnet.js in manifest" | |
| exit 1 | |
| fi | |
| echo "==> Copying $DOTNET_JS -> dotnet.js" | |
| cp "dist/wwwroot/_framework/$DOTNET_JS" "dist/wwwroot/_framework/dotnet.js" | |
| - name: Prepare Blazor build folder | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| mkdir -p build | |
| mv dist/wwwroot/* build/ | |
| - name: Upload Blazor build artifact | |
| uses: actions/upload-artifact@v6 | |
| if: | |
| github.repository_owner == 'ni' && startsWith(github.ref, | |
| 'refs/heads/main') | |
| with: | |
| name: ${{ env.APP_NAME }}-build | |
| path: ${{ env.APP_DIR }}/build | |
| cache-slcli: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| cache-key: slcli-homebrew | |
| steps: | |
| - name: Restore Homebrew cache | |
| uses: actions/cache@v3 | |
| with: | |
| path: /home/linuxbrew/.linuxbrew | |
| key: brew-cache-${{ runner.os }}-slcli | |
| - name: Ensure slcli is installed | |
| run: | | |
| eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" | |
| brew tap ni-kismet/homebrew-ni | |
| if ! command -v slcli &>/dev/null; then | |
| brew install slcli | |
| fi | |
| echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH | |
| - name: Verify slcli | |
| run: slcli --version | |
| generate-combined-matrix: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Generate app matrix | |
| id: set-matrix | |
| run: | | |
| BASE_DIR="examples/Web Applications/Framework Examples" | |
| APPS=() | |
| for framework_dir in "$BASE_DIR"/*; do | |
| if [ -d "$framework_dir" ]; then | |
| FRAMEWORK="$(basename "$framework_dir")" | |
| for app_dir in "$framework_dir"/*; do | |
| if [ -d "$app_dir" ]; then | |
| APP_NAME="$(basename "$app_dir")" | |
| APPS+=("$FRAMEWORK/$APP_NAME") | |
| fi | |
| done | |
| fi | |
| done | |
| # Compact JSON (single line) | |
| if [ ${#APPS[@]} -eq 0 ]; then | |
| JSON_MATRIX="[]" | |
| else | |
| JSON_MATRIX=$(printf '%s\n' "${APPS[@]}" | jq -R . | jq -cs .) | |
| fi | |
| echo "matrix=$JSON_MATRIX" >> "$GITHUB_OUTPUT" | |
| package-deploy: | |
| if: | | |
| always() && | |
| github.repository_owner == 'ni' && startsWith(github.ref, 'refs/heads/main') && | |
| !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') | |
| needs: [build-node, build-blazor, cache-slcli, generate-combined-matrix] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app_dir: ${{ fromJSON(needs.generate-combined-matrix.outputs.matrix) }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Parse app | |
| run: | | |
| APP_DIR="examples/Web Applications/Framework Examples/${{ matrix.app_dir }}" | |
| APP_NAME="$(basename "$APP_DIR")" | |
| echo "APP_DIR=$APP_DIR" >> $GITHUB_ENV | |
| echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV | |
| - name: Create build folder | |
| run: mkdir -p "${{ env.APP_DIR }}/build" | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ${{ env.APP_NAME }}-build | |
| path: "${{ env.APP_DIR }}/build" | |
| - name: Restore Homebrew-slcli from cache | |
| uses: actions/cache@v3 | |
| with: | |
| path: /home/linuxbrew/.linuxbrew | |
| key: brew-cache-${{ runner.os }}-slcli | |
| - name: Add slcli to PATH | |
| run: echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH | |
| - name: Package into .nipkg | |
| working-directory: ${{ env.APP_DIR }} | |
| run: slcli webapp pack build/ --output "${{ env.APP_NAME }}.nipkg" | |
| - name: Upload .nipkg artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: ${{ env.APP_NAME }}.nipkg | |
| path: "${{ env.APP_DIR}}/${{ env.APP_NAME }}.nipkg" | |
| - name: Login to SystemLink | |
| run: | | |
| slcli login --profile ghActions --url "${{ secrets.SL_API_URL }}" \ | |
| --api-key "${{ secrets.SL_API_KEY }}" \ | |
| --web-url "${{ secrets.SL_WEBSITE_URL }}" \ | |
| --workspace "${{ secrets.SL_WORKSPACE }}" | |
| - name: Deploy webapp to SystemLink | |
| working-directory: ${{ env.APP_DIR }} | |
| run: | | |
| pkg="${{ env.APP_NAME }}.nipkg" | |
| WEBAPP_NAME="${{ env.APP_NAME }}_PROD" | |
| WEBAPP_ID=$(slcli webapp list --workspace "${{ secrets.SL_WORKSPACE }}" --filter "$WEBAPP_NAME" --format json | jq -r '.[0].id // empty') | |
| if [[ -z "$WEBAPP_ID" ]]; then | |
| echo " * Webapp does not exist -- publishing new" | |
| slcli webapp publish "$pkg" --name "$WEBAPP_NAME" --workspace "${{ secrets.SL_WORKSPACE }}" | |
| else | |
| echo " * Webapp exists -- updating" | |
| slcli webapp publish "$pkg" --id "$WEBAPP_ID" | |
| fi | |
| echo "**Deployed $WEBAPP_NAME**" |