Publish Application Workflow

March 26, 2026 ยท View on GitHub

This reusable GitHub Actions workflow automates the process of building and deploying .NET and/or SPA (Single Page Application) projects to Azure. It provides flexibility to build and deploy either or both project types, supporting deployment to Azure Web Apps and/or Azure Storage.

Functionality Summary

The Publish Application workflow includes the following features:

  • .NET Backend Build:

    • Restores NuGet packages and builds the .NET application.
    • Publishes the .NET application to a build output directory.
    • Supports adding private NuGet sources based on provided accounts and secrets.
    • Adds a GitHub release asset, if applicable, with the .NET application
  • SPA Frontend Build:

    • Installs NPM dependencies and builds the SPA application using a specified NPM script.
    • Uploads the built SPA artifact and optionally a persisted documents file.
    • Adds a GitHub release asset, if applicable, with the SPA application
  • Deployment to Azure:

    • Deploys the .NET and/or SPA application to Azure Web App.
    • Deploys the SPA application to Azure Storage for static website hosting.
    • Supports deployment methods: azure-webapp and azure-storage.
  • Conditional Execution:

    • Workflow steps are conditionally executed based on the inputs provided.
    • Skips .NET steps if dotnet_folder is not specified.
    • Skips SPA steps if spa_folder is not specified.
    • Build jobs run regardless of whether Azure credentials are configured.
    • Deployment jobs only run if Azure credentials are provided.
    • Release assets are created whenever builds run, regardless of deployment configuration.

Configuration Options

Common Inputs

Input NameDescriptionRequiredDefault Value
environment_nameSpecifies the GitHub environment to use while building and for Azure authenticationYesNone

.NET Build Inputs

Input NameDescriptionRequiredDefault ValueComments
dotnet_folderPath to the .NET project folderNoNoneOmitting skips .NET-related steps
global_json_folderPath to the folder containing global.jsonNo.Ignores dotnet_folder when resolving path
nuget_accountsComma-separated list of GitHub accounts for NuGet sourcesNoRepository ownerSkipped if tokens are not provided
npm_accountsComma-separated list of GitHub accounts for NPM sourcesNoRepository ownerSkipped if tokens are not provided
dotnet_configuration.NET build configuration (e.g., Release, Debug)NoRelease

SPA Build Inputs

Input NameDescriptionRequiredDefault ValueComments
spa_folderPath to the SPA project folderNoNoneOmitting skips SPA-related steps
spa_deployment_methodSPA deployment method: azure-webapp or azure-storageNoNoneRequired to deploy
spa_version_envEnvironment variable to set with the version numberNoVITE_VERSIONe.g. REACT_APP_VERSION for React
npm_build_scriptNPM script used to build the SPA applicationNobuild
npm_dist_folderPath to the SPA distribution folder (relative to spa_folder)Nodist
persisted_documents_filePath to the persisted documents file to copy to .NET build folderNoNone
npm_analyze_scriptNPM script to run after build for analysisNoNone
analysis_artifactsFull path to files to upload as analysis artifacts (glob pattern)NoNone

Azure Configuration Inputs

Input NameDescriptionRequiredDefault Value
azure_client_idClient ID for Azure deploymentNoNone
azure_tenant_idTenant ID for Azure deploymentNoNone
azure_subscription_idSubscription ID for Azure deploymentNoNone
azure_webapp_nameAzure Web App name for deploymentNoNone
azure_webapp_slot_nameAzure Web App slot name for deploymentNoNone
azure_storage_accountAzure Storage account name for deploymentNoNone
azure_storage_containerAzure Storage container name for deploymentNoNone

Environment Variables

If an environment is configured, variables configured for the specified environment are used as shell environment variables when building the code.

Required Variables or Inputs

The workflow requires the following Azure configuration values to be provided either as:

  • Workflow inputs (as shown in the table above), or
  • Repository/Environment variables with these names:
Variable NameDescriptionRequiredDefault Value
AZURE_CLIENT_IDClient ID for Azure deploymentNo (will skip deployment if not specified)None
AZURE_TENANT_IDTenant ID for Azure deploymentNo (will skip deployment if not specified)None
AZURE_SUBSCRIPTION_IDSubscription ID for Azure deploymentNo (will skip deployment if not specified)None
AZURE_WEBAPP_NAMEAzure Web App name for deploymentRequired if deployment_method is azure-webappNone
AZURE_WEBAPP_SLOT_NAMEAzure Web App slot name for deploymentNoProduction
AZURE_STORAGE_ACCOUNTAzure Storage account name for deployment (azure-storage method)Required if deployment_method is azure-storageNone
AZURE_STORAGE_CONTAINERAzure Storage container name for deployment (azure-storage method)Required if deployment_method is azure-storageNone

The workflow will first check for values provided as inputs, and if not found, will fall back to repository or environment variables. If neither is available, the workflow will skip deployment steps but will still build the application and create release assets.

Secrets

Secret NameDescriptionRequiredDefault Value
NUGET_ORG_USERUsername for private NuGet source (if applicable)NoNone
NUGET_ORG_TOKENToken for private NuGet source (if applicable)NoNone
NPM_TOKENGitHub Personal Access Token for private npm packagesNoNone

Example Usage Scripts

1. Deploy .NET Application to Azure Web App for development

name: Deploy .NET Application

on:
  push:
    branches:
      - master

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app.yml@v2
    permissions:
      contents: write
      id-token: write
    with:
      dotnet_folder: '.'
      environment_name: Development
    secrets:
      NUGET_ORG_USER: ${{ secrets.NUGET_ORG_USER }}
      NUGET_ORG_TOKEN: ${{ secrets.NUGET_ORG_TOKEN }}

The above example assumes that the necessary Azure configuration values are stored as GitHub environment variables for the Development environment.

2. Deploy SPA to Azure Storage for development

name: Deploy SPA Application

on:
  push:
    branches:
      - master

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app.yml@v2
    permissions:
      contents: write
      id-token: write
    with:
      spa_folder: ReactApp
      spa_deployment_method: azure-storage
      environment_name: Development
      azure_storage_account: mystorageaccount
      azure_storage_container: public
      azure_client_id: ${{ secrets.AZURE_DEV_CLIENT_ID }}
      azure_tenant_id: ${{ secrets.AZURE_DEV_TENANT_ID }}
      azure_subscription_id: ${{ secrets.AZURE_DEV_SUBSCRIPTION_ID }}

The above example shows how to provide Azure configuration values as workflow inputs, pulling from repository secrets.

3. Deploy Full Application (Backend and SPA) to Azure Web App for production

name: Deploy Full Application

on:
  release:
    types:
      - published

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app.yml@v2
    permissions:
      contents: write
      id-token: write
    with:
      dotnet_folder: '.'
      spa_folder: ReactApp
      spa_deployment_method: azure-webapp
      environment_name: Production
    secrets:
      NUGET_ORG_USER: ${{ secrets.NUGET_ORG_USER }}
      NUGET_ORG_TOKEN: ${{ secrets.NUGET_ORG_TOKEN }}
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

The above example assumes that the necessary Azure configuration values are stored as GitHub environment variables, and only passes the required NuGet secrets.

Notes

  • The permissions: id-token: write is required for Azure deployment workflows to enable OIDC authentication with Azure.
  • NUGET_ORG_USER, NUGET_ORG_TOKEN, and NPM_TOKEN should already be configured as organization secrets but need to be passed in.
  • global.json is required
  • Cannot override .NET SDK with another version or install multiple SDKs
  • permissions: contents: write is necessary to upload the compiled application as a release asset

Warning

While deploying the .NET application, this will delete all existing files in the destination folder before deploying the updated application code. This will permanently delete any local databases (e.g., SQLite .db files) or other data files stored on the server.