Hugo on Azure with Static Web Apps
Tags: azure, github, devops
Published: 2021-05-18 18:21:34

I have few web sites based on [Hugo](https://gohugo.io/) framework currently running as Web Apps on Azure App Service Plan at the Shared tier: one of the least expensive options with the ability to use a custom domain names, you can learn more about the [differences beteween hosting plans here](https://docs.microsoft.com/en-us/azure/app-service/overview-hosting-plans).
At the time I renovated my sites with Hugo 3 years ago this was the easiest path to move to Azure. Now I want to improve my static web sites in few areas: #1 automate the deployment workflow and #2 use less resources. #3 I also want to leverage GitHub Actions.

## GitHub Actions
As [GitHub documentation](https://github.com/features/actions) describes it:
> GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub.

GiHub Actions are a powerful way to define YAML based pipelines triggered by events. There is an excellent post describing how to use [GitHub Actions to publish Hugo websites](https://ruddra.com/hugo-deploy-static-page-using-github-actions/) and from this source I discovered the GitHub Actions for Hugo, available from the [Actions marketplace](https://github.com/marketplace?type=actions).
{% github peaceiris/actions-hugo %}
With it you can build your Hugo content and then deploy in a subsequent step. 
I could rely on the [Static Web Site on Azure Storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website) as the deployment target to fulfill my objective #2 but there is another, even better, option to publish static content with an automated approach: *Azure Static Web Apps*! 

## Azure Static Web Apps
[Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/) is _a service that automatically builds and deploys full stack web apps to Azure from a code repository_: exactly what I needed for objectives #1, #2 and also #3 as GitHub Actions are supported.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80ynayprid5r41ts55pr.png)  These are the steps to reach my goal:
* Create an Azure Static Web Apps
* Integrate GitHub Actions with Azure Static Web Apps
* Trigger my GitHub Actions only when needed
* Publish my updates to a separate environment before moving into production

Let's start with the activities!
### Hugo in Azure Static Web Apps
The value of Azure Static Web Apps sits in its close integration with the code repository and the CI/CD pipeline. You can find a [Hugo focused walkthough here](https://docs.microsoft.com/en-us/azure/static-web-apps/publish-hugo): for the sake of brevity let's say I have an existing GitHub repository containing my Hugo site.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45byjtf7qfmmyzfp4vdf.png)  As you can see from the picture above, I am connecting the newly created Static Web App to my GitHub Account and the _main_ branch of my web site with Hugo repository.

## Ready to use GitHub Actions
This integration does create a new [GitHub Action workflow in my repository](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow), well explained in the documentation. The main steps are the following:
```yaml
on:
  push:
    branches: [main]
    paths-ignore: '.github/workflows/**'
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches: [main]
    paths-ignore: '.github/workflows/**'
```
With the controls on trigger `paths-ignore: '.github/workflows/**'` I prevent the workflow from running when I edit my Actions.
The workflow continues with the definition of build & deploy job triggered by push or PR:
```yaml
build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v0.0.1-preview
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_GRAY_DUNE_09D67E003 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
          app_location: "/" # App source code path
          api_location: "api" # Api source code path - optional
          output_location: "public" # Built app content directory - optional
          ###### End of Repository/Build Configurations ######
```
The job triggered once a PR close event is detected is similar:
```yaml
  close_pull_request_job:
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    steps:
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@v0.0.1-preview
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_GRAY_DUNE_09D67E003 }}
          action: "close"
```
Apart from the secrets defined while provisioning the Azure Static Web App and used to deploy the built Hugo site, the interesting part is the usage of the GitHub Action `Azure/static-web-apps-deploy@v0.0.1-preview`: what is it?
#### What is Oryx?
The GitHub Actions workflow, created in the project repository, does use the [Azure Static Web Apps Deploy GitHub action](https://github.com/marketplace/actions/azure-static-web-apps-deploy) from the marketplace. This reusable Action utilizes Oryx system to build both static applications and Azure Functions for API and then deploys it. You can find more information on Oryx repository at https://github.com/microsoft/Oryx and on [how it does detect & build Hugo applications](https://github.com/microsoft/Oryx/blob/master/doc/runtimes/hugo.md).

### Verify changes before publishing
As the only author of my web sites, I am tempted to expedite the process to post something new: open VS Code, change the markdown files, git commit & push to the _main_ branch, followed by build & deploy to the public site! It seems simpler only if you do not account for any error: forcing yourself to follow a more rigorous process, while automating it as much as possible, is the way to go. 
With [branch protection rules](https://docs.github.com/en/github/administering-a-repository/managing-a-branch-protection-rule) you can demand that a pull request on a branch must be reviewed before merging into the protected branch, _main_ in my case, preventing the author  from pushing directly into it. ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bujvgrbnw7zmm1y24kjz.png)  Even by requesting the minimum of approvers, I am 1 short on my team of one. *For the time being* I will force myself to start PRs and not leverage branch protection.  ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4udtboib9z0mw2d4wf6c.png)  In the previous screenshot I created a branch for my commit and started a PR. ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1g0l5v1a2256xmka9t7.png)  This is the [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) I am starting, the final goal is to merge that branch into the _main_ one.  What does happen when we start a PR?

### PRs and Environments 
Azure Static Web Apps is so well integrated with the GitHub Actions that it translate pull requests (PR) into [staging environments, so you can review the changes before publishing it in front of your users](https://docs.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests).
We just created a branch and started a PR: the following screenshot show what the workflow, created for us by Azure Static Web Apps, does provide.  ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7piir2ovwrmstw7mqfb.png) The GitHub Action has been triggered and is going to build and publish to a staging environment. ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e92h41pgd2ucz5hyfi3v.png) Once complete, we are presented with the url of the Azure Static Web Apps environment ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82azcer0r7ju6p5vykq8.png)  In the Azure Portal we see the staging environment listed for our Azure Static Web App.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5s61klkw8lx3cdkei5q3.png) We have the chance to verify our changes: Once we are ready to apply these to the public site, we go back to the PR and merge it into the _main_ branch. ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dda3cjt3r3rgu3haornn.png) The GitHub Action will then start two job runs to close the pull request, remove the staging environment, build and publish the Hugo site on the production environment. 

## At last!
In this article we explored the great CI/CD integration provided by Azure Static Web App with GitHub Actions, for Hugo static site and for [many other frameworks](https://docs.microsoft.com/en-us/azure/static-web-apps/overview#what-you-can-do-with-static-web-apps) as well.
With Azure Static Web App I will decommission the App Service that is currently supporting my static sites, while keeping the [ability to have custom domain and free TLS certificate!](https://docs.microsoft.com/en-us/azure/static-web-apps/custom-domain?tabs=azure-dns). 
As my sites are personal/hobby related, I will be able to [use it for free](https://azure.microsoft.com/en-us/pricing/details/app-service/static/)!