Azure Static Web Apps from Azure DevOps Releases
Tags: devops, staticwebapps, singlepageapplications, azurestaticwebapps
Published: 2021-08-20 22:40:44

[Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/overview) is an awesome new option for deploying single page applications, however I had specific goals that the current documentation didn't quite address, so here is how I met them.

## My Goals
1. Deploy to Azure Static Web Apps
2. Deploy the same code to different environments (i.e. Sandbox, Test, Production)
3. Automatically deploy to Sandbox (aka Test/Staging)
4. Require approval to deploy to Production

The [Microsoft Documentation for publishing from Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/publish-devops) builds and deploys in a single step via Pipelines, however that doesn't support multiple deployments from same artifacts or an approval step.

All of those goals are possible using Azure DevOps, however it took some additional steps to get them working together.

## Prerequisites
1. A Single Page Application published as an Artifact built using Azure Pipelines
    * My artifact contains two builds of an Angular app, 'sandbox' and 'prod'
    * I happened to use an Angular app, but you can apply this to any single page application framework, such as React, Vue, Ember.js or Svelte.
2. The Deployment Token from an already-created Azure Static Web App
  * [Create a Static Web App section](https://docs.microsoft.com/en-us/azure/static-web-apps/publish-devops#create-a-static-web-app)

## Configure Your Release
1. In your Azure DevOps project, go to Pipelines, then Releases
2. Create a new Release Pipeline (using the "+ New \/" button)
   ![Pointing to the Create a new Release Pipeline button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwwni78hkkdypvlfa8l5.png)
3. Select 'Empty job' as the Template
   * We will be creating ours from scratch
   ![Pointing to the Empty Job link](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p45odanbj4hsis0hlfvc.png) 
4. Name your first Stage
   1. The Name can be whatever you like. I used 'Production Deployment'
5. In the Artifacts, select the Artifact that you already built
   1. Select Build as Source type
   2. Select your Source - This is the Name of your Artifact from the Prerequisites.
   3. You can update the 'Source alias' to a simpler name if you prefer
      * This will be used in your pipeline later
   4. Click the "Add" button to save your Artifact
   ![The Artifact selection dialog](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uxmriwi3q478l3qcfw8b.png)
1. Now click the "View stage tasks" link ("1 job, 0 tasks") on your existing Stage
  ![Task Link Click](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ri1nyrcvgesqobukt5k9.png)
1. Click "Agent job" above the tasks to edit the default settings
   1. Change the Agent Specification to a recent Linux build, such as `ubuntu-20.04`
   ![Agent Job settings showing ubuntu-20.04 selected for Agent Specification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vnfb7rqbr3306ea3268.png)
6. Next to "Agent Job", click the "+" button to add a new Task
  ![Add Task to Job](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gkeobse8qbv41gir8ccn.png)
	7. Find the "Deploy Azure Static Web App" task (from Microsoft Corporation) and click "Add"
         ![Add Deploy Azure Static Web App Task](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ggz5a269lj875vyxhyo.png)
	  * At the time of this blog post, it is currently in PREVIEW and at version 0.* (preview)
	8. Fill in the following fields of the task:
	  1. Display Name - Can be anything you want
	  2. App Location - Set to path of your built app in the artifact	  
	     * Use the form "\<ArtifactName\>/\<BuildName\>/", i.e. `AngularBuildArtifact/prod/`
	  3. Output Location - Set to path of your built app in the artifact,
	     * Use the form "\<ArtifactName\>/\<BuildName\>/", i.e. `AngularBuildArtifact/prod/`
	  4. Skip App Build - Set to `true`/checked. (The app is already being built and stored as an Artifact)
	  5. Azure Static Web Apps Api Token - Fill in with your Deployment Token variable: `$(deployment_token)`
		 * Follow Steps 5-10 in the [Create the Pipeline Tasks](https://docs.microsoft.com/en-us/azure/static-web-apps/publish-devops#create-the-pipeline-task-in-azure-devops) section to configure a secret variable for your Deployment Token
            ![Full Task Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ld3664c5rqwt9mbzrgna.png)
	  6. Save your Release
            * You can find my YAML for this task [at the end of this post](#yaml-static-web-app)

* **Note:** I didn't have an Azure Functions API or routes.json, so I have left the remaining fields blank. We are also skipping the app build, so we don't need to provide an App Build Command.

## Congratulations! You can now run the Release to deploy to Azure Static Web Apps.
---
{% details When this post was originally, a workaround was required for a docker error. That is no longer required, however the details can be found by clicking this if you are curious. %}
* **Note**: If you run this task now, it will fail with an error in the task: 
> docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination::/working_dir Type:bind Source:/var/lib/docker/volumes/8d90060c5907d68a281862c7f31dcb71efe24e52511ac78682a1e5e5dd27b0af/_data Options:[rbind]}: mount destination :/working_dir not absolute: unknown.
As of the writing of this post, unfortunately there is a known issue within the Azure DevOps Static Web Apps task, however there is a workaround.
  * More information can be found in [this GitHub issue](https://github.com/Azure/static-web-apps/issues/463). The workaround is based on [this comment](https://github.com/microsoft/azure-pipelines-tasks/pull/14807#issuecomment-868593099) in a related pull request.
  * If the issue is resolved, please leave a comment on this post and I will update it.
## Workaround Steps
1. Add a Bash Script task *above* the Static Web Apps task
  ![Add Second Task to Release](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w9m461z8smfq2tv9nms8.png)
  ![Add Bash Script Task](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6bdu3uienhw9c164kbsy.png)
  ![Move Bash Script Task First](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/djhi7xbwtdfwz5ldj08g.png)
2. Change the Type to 'Inline'
2. For the script command to run add the following command: `echo '##vso[task.setvariable variable=BUILD_SOURCESDIRECTORY]$(System.DefaultWorkingDirectory)'`
  * This command will set the necessary environment variable that the Static Web Apps requires.
{% enddetails %}

---
### Bonus Content - Adding Approval to the Stage
1. On the Pipelines tab, click the Pre-deployment Conditions button (at the left of the Stage button)
  ![Location of Pre-Deployment Conditions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vq29zc5ssjc1phc0il4z.png)
2. Enable Pre-Deployment Approvals
  ![Location of Pre-deployment approvals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su39yvmt2n1tixxbz7wc.png)
3. Fill in Approvers from your organization
  ![Demonstration of Required Approvers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a09iqp22ch70fsbyel2p.png)
4. Feel free to set the rest of the settings as necessary for your situation. 

---
## YAML for the Static Web App Task <a name="yaml-static-web-app"></a>
```yaml
variables:
  deployment_token: '<YourDeploymentToken>'

steps:
- task: AzureStaticWebApp@0
  displayName: 'Static Web App - Production Deployment'
  inputs:
    app_location: AngularBuildArtifact/prod/
    output_location: AngularBuildArtifact/prod/
    skip_app_build: true
    azure_static_web_apps_api_token: '$(deployment_token)'
```