Setting Up This Website - Static Web Apps in Azure

Posted on Dec 14, 2021

This website, right now, is set up as a static web application in Azure. Why, you ask? Because it can be. Because it’s clever. Because it can be useful. Because it’s cheap. Because it’s easy. Mainly because it’s cheap and easy. I didn’t come about this initially and, actually, when I first started looking into this a few years ago the concept was still fairly new and Azure had most of the features I will end up using for this site in preview, if at all.

If you want to skip the preamble and get down to business go ahead and skip to Deploying a Hugo Site on Azure

Table Of Contents

The Roads Not Traveled

I’ve deployed some other sites through various mechanisms and I would like to point out, prior to getting started, why I don’t think that they completely make sense for my purposes but why they might make sense for others. The Internet, technology in general, and people in particular, are varied things. For a personal site thinking about these choices in any great depth may not have any appreciable impact, and in fact, there may be cases where they’re more appropriate but it’s worth having a brief discussion.

WSYWIG Content Management Systems

If I’m showing my age, I’m sorry, but WSYWIG (what you see is what you get) CMS products were where the web was moving towards when I got started in technology. It’s interesting that we’re seeing the rebound these days and there are a few reasons why. CMS systems, especially ones designed to intake human-readble designed content, generally aren’t great at automation. They are very popular, however, and once set up they allow people to generate their content quickly and easily. Marketplaces with themes ready-made make it simple to get something that looks nice enough and there is an entire industry based on developing templates on a contract basis so outsourcing is available. These systems also do a great job of managing all of the “back end” stuff. Some are very good at having multiple users contribute. You can do backups and restores with a few clicks (generally). You don’t need to do much, if at all, to get the cross links and all that functional. It’s good stuff. It does a lot but it does it at a cost.

Part of the cost is transparency. Generating your own templates can be more involved than what most people may wish to take on–PHP is one language in particular that I’ve not had the best experiences with and it may not be obvious what includes may be required to get the functionality you’d like if you’re trying to write your own template or plugin. Some CMS systems also won’t make rolling back changes terribly easy. Perhaps you broke something or accidentally deleted a post? You may be able to do a restore but there are potentially other changes that were made in the interim. Or maybe you can’t track if someone else made that change. Certain CMS may be better about this but it’s still doing a lot and that brings up the last con–they’re big. They’re relatively complicated systems that are constantly running jobs in the background and dynamically inserting their content and they can end up requiring more resources than would be ideal or just being generally slow. They are also commonly targeted for exploitation and with so many mechanisms, and the administration component being accessible from the Internet, there is generally a good amount of attack surface.

Hosted Web Services

Getting away from dynamic systems we have the OG static site. Again, showing my age, but in the Geocities era, if you didn’t pay for a cgi-capable hosting service, this is all you had. Hosted services have come down in price and gone up in capability significantly and many of the drawbacks that will be mentioned are addressable but they do require effort and may still carry forward their limitations. With many common plans for various hosting providers you can very easily integrate buying a domain and hosting as well as being able to run dynamic content (commonly PHP) within reasonable constraints for a low-cost plan.

You interact with a hosted web service using SFTP (FTP over SSH) which is much more secure than the previously-ubiquitous plain-text FTP protocol however authenticating is generally limited to username and password. Managing users for a hosting provider’s account can be tedious at best (non-existant at worst) and doesn’t have a lot of intelligence or technology behind it, which is what spawned the all-in-one nature of the modern CMS.

Enter the Modern Static Site

This isn’t new but it is, probably, the newest pattern to build a good site. There is an entire movement behind building these sites over at jamstack.org and, really, it makes a lot of sense. The J, A, and M in “Jamstack” stand for JavaScript, APIs, and Markup. JavaScript the enables rich and interactive experiences of the web and is able to interact with APIs to enhance sites and web apps with dynamic content. Markup is the language used to turn the pre-generated content, like this post, into a web site, without fiddling with HTML tags and the like. There’s value, as a business, in having generated static sites as they reduce the attack surface on the front end and allow for collaborative work using git in addition to the ability to heavily automate content generation. There is value, as an individual, in generally reducing complexity and making it easier to have a functional website.

There are a number of places that support deploying static sites like Netlify, GCP, AWS, and Azure. There are also a number of generators like Jekyll, Gatsby, and Hugo. The different platforms provide various services, supported generators, and integrations. The various generators provide support for various features and run on a (usually) specific programming language platform (e.g. Hugo is built with Go, get it? HuGo? and it uses the Go templating language) so you can find one that is geared to your wants and needs. I’ve chosen Hugo because it was the most straight-forward to begin with. I’ve since needed to adjust and merge templates to create different kinds of content and incorporate a certain amount of functionality but those are posts for another day.

Deploying a Hugo Site on Azure

There’s a few ways to go about this and I may be taking the road less travelled using Azure DevOps. I do have a GitHub account but I also do enjoy some of the aspects of Azure DevOps so I’m going in this direction. You can use whichever method you think works best for you–there is validity in using a GitHub account for many reasons. That’s just not what I’ve done here.

Setting up local files

You can’t just click go–you need a couple of things set up. Firstly, you need to have an Azure account spun up. Then you’ll need to have Azure DevOps going–and that was basically a couple of clicks. You’ll need some familiarity with git and I recommend Learn Git Concepts Not Commands as a primer (or a refresher–not judging). I did this on a macOS device so I used homebrew to install everything. You can get it at brew.sh. There are a couple of things you may need:

  • git (obviously)
  • hugo (obviously)
  • Git Credential Manager from Microsoft (brew install git-credential-manager-core). This may also install .Net core–I already had it installed so I’m not completely certain. It’s not required but it makes this process very simple.

Ideally, you would git init the directory that you were going to use for your Hugo site so that when you did hugo new site you could just track everything from jump. If you’ve already created a Hugo site you can use the following commands to make it a repo and add everything in there:

git init
git add -A

Easy enough. If you don’t have any idea where to start with this technology but are interested in trying it out to see what the workflow is like I’ll drop a script in here to get your local up to speed. Some lines are taken from the Hugo Quick Start page.

mkdir HugoOnAzure
cd HugoOnAzure
git init
hugo new site HugoOnAzure
# we need a theme
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke
# no need to be cute just swap out the URL in config.toml using an editor
sed -i -e "s/example.org/yourdomain.com/g" config.toml
hugo new posts/my-first-post.md
# this will generate some info for your first post file
# there's a lot to this but it's a quickstart
# make sure to set 'draft' to false or to remove that line
sed -i -e "s/true/false/g" posts/my-first-post.md
# add something in there. this is 100% not the best way to edit files
echo "Hello world!" >> posts/my-first-post.md 

Setting up Azure DevOps

  1. In the Azure DevOps portal, ensure you have an organization. From here, add a new project using that nifty + New Project button at the top right.
  2. Create a new repository by clicking the + right next to the name of your project under the Azure DevOps logo at the top left.
  3. If you didn’t uncheck “Add a .gitignore” then you’ll be greeted with an empty repo and no really good information on how to proceed. I’ll provide some of that information presently. Take note of the name of the organization that you created in Azure DevOps and copy the URL of the page you’re currently looking at because you’ll need this to set up the remote location for the repository. Replace “organization”, “project”, and “repo-name” with the values that you need.
git remote add origin https://organization@dev.azure.com/organization/project/_git/repo-name
git push -u origin --all
  1. If you did uncheck that then you’ll have some information on how to push an existing repository already filled in with your repo information. Copy and paste that stuff into your shell and you should be able to push everything up to Azure DevOps. This step is where the git credential manager comes in to play–it’ll open up a browser window for you to log in (2FA and all that if you have it set up and you should) and makes it very convenient to get authenticated.

Creating a static web app

Here, the metaphorical rubber meets the proverbial road. I’d create a resource group for this just for organization purposes but you do you.

  1. You’ll go ahead and type “Static Web App” in the search bar for the Azure Portal to get into the menu for creating the static web app. The important thing here is to select “Other” in the Source parameter as we are going to use Azure DevOps as the source. It’s set up by default for GitHub and this is a very good marketing move as it’s extremely likely that a lot of people are coming in from GitHub but unless your org is paying for GitHub it’s more likely that they’ve got Azure DevOps. The free tier is pretty beefy so jump on into it.
  2. Click on the Go To Resource button (yeah, I know) and, when you get there, click on Manage Deployment Token in the top menu for the “Overview” screen. If you leave the “Overview screen to look around this will disappear so keep your eyes peeled.
  3. Go back to your repository in Azure DevOps and in the “Files” pane of the repository you should have a Set up build button at the top right (since you did definitely commit some files and push to your remote location in git like I mentioned in Setting up local files, right?).

Digging into the pipeline

Now it’s about to get real. We need to do a couple of scripty things. If you think this looks like a Docker buildfile I won’t disagree with you. The philosophy is the same here–a disposable environment that can build the thing. The thing, in this case, is our Hugo site. Based on your content and themes you may not need much at all. Some themes, however, require a little extra. That’s up to you to handle.

💡 As an aside, this looks a lot like a Docker buildfile and I’ve done a tiny bit of work on that before. Personal project, really, but it was tied into the WNYC Audiogram project (which I’m sure has been forked to hell with no credit) that I hoped to extend to support subtitles (haven’t gotten around to it). I’ve written about it on Medium @mark_diaz.

We need to drop that token in there as a variable. Go ahead and do that and name it TOKEN. A sturdy name for a sturdy token. I chose to keep the token a secret and we’ll see whether or not it will bite me in the ass.

To write the pipeline file YAML script… well. The best way to do that, in my experience, is to see a working example. I grabbed this one from Unravelled Development. They’ve got a nifty feature here with a staging token and you should check out their post for more info on that (it’s very good):

trigger:
- main

stages:
  - stage: 'GenerateHugo'
    displayName: 'Generate hugo website'
    jobs:
      - job:
        pool:
          vmImage: ubuntu-latest
        workspace:
          clean: all
        steps:
        - checkout: self
          displayName: 'Checkout repository including submodules'
          submodules: true  # true so Hugo theme submodule is checked out
        - script: wget https://github.com/gohugoio/hugo/releases/download/v0.83.1/hugo_0.83.1_Linux-64bit.deb -O '$(Pipeline.Workspace)/hugo_0.83.1_Linux-64bit.deb'
          displayName: Download Hugo v0.83.1 Linux x64
        # 2. Installs Hugo executable
        - script: sudo dpkg -i $(Pipeline.Workspace)/hugo*.deb
          displayName: Install Hugo
        - task: AzureStaticWebApp@0
          condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
          inputs:
            app_location: '/'
            app_build_command: 'hugo'
            output_location: '/public'
            azure_static_web_apps_api_token: '$(TOKEN)'
        
        - task: AzureStaticWebApp@0
          condition: ne(variables['Build.SourceBranch'], 'refs/heads/main')
          inputs:
            app_location: '/'
            app_build_command: 'hugo'
            output_location: '/public'
            azure_static_web_apps_api_token: '$(STAGING_TOKEN)'

# below added by Mark
# really good stuff here. Important to make sure that the submodules are checked out as that is the recommended way to store themes.
# themes are worth discussing but that's more complicated than this post needs to be. I'll get there, I promise.
# in plain text this build file checks out the repo, downloads and installs hugo on an ubunt container, and then 
# builds your source material with the hugo installed in the container and deploys it to your web app using 
# that token we dropped in there as a variable.

So I got a fun error: ##[error]No hosted parallelism has been purchased or granted. To request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request. This feels like the Azure equivalent of “McFly, you bozo, those boards don’t work on water. Unless you’ve got powwwwaah.” I submitted a request but I don’t know when it will come through. I’m writing this stream of consciousness now to see what the feeling of it is like. I’m not even sure what it means by “parallelism” because this seems relatively straightforward but maybe I’m missing something. After searching for a while it seems that you need to request “parallelism” for a private repo via that form. This script doesn’t feel terribly parallel but this is free-tier so it is what it is. Allegedly this can take days to be addressed.

30 MINUTES LATER Booooring. I know I just submitted the form about 20-30 minutes ago but yes, it’s very boring. The waiting, that is. Quite dull and uneventful. I haven’t come up with any great ideas just yet–waiting to get this website up. Yes, I’m using this process to make this very same website. Talk about dogfooding.

I’m actually very big on dogfooding. Not eating one’s dog’s food but “eating one’s own dogfood” which is an idiom that basically equates to “suffer what you cause others to suffer.” There is a symmetry there. An inherent empathy. I dig it. This will give me time to figure out the font problem I seem to be having with this template. It is very likely of my own making.

💡 At some point in here I got an error that the remote repository was ahead of my local. That’s not a good problem to have. I needed to do git config pull.rebase false and then do a git.pull on it to make a git push work. Just a heads up. Also, it’s been a few hours and still waiting on that form to come back to me for my free tier of Azure DevOps build. Seriously, team, I know we want to prevent abuse but also c’mon now.

Setting up a self-hosted agent

ONE DAY LATER Ok, I’m going to install a self-hosted agent. I have a Linux box that’s hanging out and running my asterisk server. It’s idle most of the time that it’s on so why not? Grabbing the agent from the page Deploy an Azure Pipelines agent on Linux. The vibe here is a lot like a Jenkins agent, if you’ve ever deployed one of those. The concepts here aren’t new but they are, possibly, put together in a novel manner. There’s a couple of things to do and several considerations to make–most of them are on that page but I’ll drop a script here to handle the files.

# this URL may change--the page linked above will have the latest
wget https://vstsagentpackage.azureedge.net/agent/2.196.1/vsts-agent-linux-x64-2.196.1.tar.gz
sudo adduser vstsagent #this is a little bit of a process but it should be straightforwward
cd /home/vstsagent
sudo mkdir agent
cd agent
sudo tar -xvf vsts-agent-linux-x64-2.196.1.tar.gz

The files are good to go in the home directory of the user vstsagent (ymmv based on what flavor you’re using but this is pretty common stuff nowadays). You’ll need a personal access token to register the agent. You can click on the person icon at the top right of the page in Azure DevOps and go down to personal access tokens. From there expand all scopes and pick Agent Pools (read and manage). If this seems a bit pedantic… it isn’t. It’s extremely important to understand that a PAT is basically a login and password put together. So yes, please ensure that the scope here is correct and don’t go making PATs at random. Also, and I know it tells you but it bears repeating. Save the PAT until you’re done with it (thanks, Blake Snyder) because you can’t get it back. You’ll need to generate another one.

su vstsagent # you remember the password you gave this user, right?
./config.sh # it's got ascii art it's legit. loving the resurgence of the command line
💡 When it asks you to join a pool and says Default it really means it will put the agent in the pool called Default. If you made a pool already go ahead and type its name in there. I now have a pool called Default and that’s fun, I guess. Going through the configuration process again you might be able to move it. At this stage it isn’t important but it’s worth noting in case you’re running up against issues

We are now presented with the choice of running it as a service or on demand. I’m going to go ahead and run it as a service and I will do that by executing sudo ./svc.sh install vstsagent and it will install and run as the user vstsagent which is not privileged on this device. You should definitely take a look at the script before running it in the event that some element there doesn’t work out for you or needs to be adjusted. You also may need to exit the vstsagent user session as, at least how I want it, that account cannot sudo. I didn’t have any issues and was able to start the agent manually by typing sudo ./svc.sh start. It should automatically start on reboot.

Go back to your project and into Project Settings (it’s at the bottom left). Ensure that whatever pool you added this agent to is available to the project. I haven’t tried running the pipeline again yet but I’m hoping it would figure out that I had an agent available. Ok it complained and it still tried to go to the hosted pipeline. I added the following to the YAML file.

pool:
  name: Default
  # this 'pool' section already exists in the yaml posted above. 
  # just add the name entry to it
  # this name may also be case-sensitive. 

It’s now asking for permission to access a resource. It will let you know in the pipelines area and you can permit it with a click which is nice. It looks like this is to ensure you don’t run the pipeline on something you shouldn’t be.

Ok great the bash script tanked. Let me actually look at this pipeline and adjust it. I may already have Hugo installed on that system anyway. The error was at the installing Hugo step and that makes a whole lot of sense since it didn’t seem to spin up the docker image like I thought it would. So now it failed at running Docker.

Starting: AzureStaticWebApp
==============================================================================
Task         : Deploy Azure Static Web App
Description  : [PREVIEW] Build and deploy an Azure Static Web App
Version      : 0.194.2
Author       : Microsoft Corporation
Help         : https://aka.ms/swadocs
==============================================================================
/bin/bash /home/vstsagent/agent/_work/_tasks/AzureStaticWebApp_18aad896-e191-4720-88d6-8ced4806941a/0.194.2/launch-docker.sh
docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/create": dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.
##[error]Error: The process '/bin/bash' failed with exit code 126

Good stuff. I already added vstsagent to the docker group with sudo usermod -a -G docker vstsagent. Let’s see if a therapeutic reboot may help.

Reboot did the trick. I probably just needed to restart systemctld but I took the easy way out. Pipeline works! So that’s how you make a pipeline and it feels good to be green But there’s still a few more things we need to do to make it work work. The website is there but we need to adjust a few things because our static web app has a boosted URL.

Summary

A lot happened in this post. We got set up with Azure DevOps and a local set of files to then put in to a repository in Azure DevOps. We created a Static Web Application. We then created a build pipeline to build the website and then deploy it. We also created the website and there has been few modifications from how it originally came (at the moment). There will be some posts on those. We had to take a detour for the CI agent as the free-tier agent takes manual approval of a request, so we went ahead and installed a Linux agent on a box I had at home. We also created a repository and checked in code (this actual website that you’re reading right now).

Good stuff. As to what’s next? Well, if you were following along and have now gone to visit your Hugo site you’ll find that it doesn’t look great. Style sheets aren’t loading, etc. It’s there but it isn’t quite functional. That’s what’s coming next.

Actually, found another problem

As I finished typing this, staged, committed, and pushed–I got another build failed. It succeeded a few hours ago.

1 error(s), 0 warning(s)
    One or more errors occurred. (One or more errors occurred. (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/post-6/index.html' is denied.)) (One or more errors occurred. (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/index.html' is denied.)) (One or more errors occurred. (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/index.xml' is denied.)) (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/post-6/index.html' is denied.) (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/index.html' is denied.) (Access to the path '/home/vstsagent/agent/_work/1/s/public/posts/index.xml' is denied.)

Let’s take a peek.

drwxr-xr-x 15 vstsagent vstsagent 4.0K Dec 15 17:19 .
drwxr-xr-x 10 vstsagent vstsagent 4.0K Dec 15 17:19 ..
drwxr-xr-x  2 root      root      4.0K Dec 15 12:15 about
drwxr-xr-x  2 root      root      4.0K Dec 15 12:15 about-mark
drwxr-xr-x  2 root      root      4.0K Dec 15 12:15 about-us
drwxr-xr-x  2 root      root      4.0K Dec 15 12:15 archives
drwxr-xr-x  2 vstsagent vstsagent 4.0K Dec 15 12:14 categories
drwxr-xr-x  2 root      root      4.0K Dec 15 12:15 contact
drwxr-xr-x  2 vstsagent vstsagent 4.0K Dec 15 12:14 css
drwxr-xr-x  2 vstsagent vstsagent 4.0K Dec 15 12:14 fonts
drwxr-xr-x  4 root      root      4.0K Dec 15 12:14 images
drwxr-xr-x  2 vstsagent vstsagent 4.0K Dec 15 12:14 js
drwxr-xr-x  5 vstsagent vstsagent 4.0K Dec 15 12:15 page
drwxr-xr-x 11 root      root      4.0K Dec 15 12:15 posts
drwxr-xr-x 12 vstsagent vstsagent 4.0K Dec 15 17:19 tags

I’ve been seeing some folders still have ownership of root/root. They still have read access so it should be fine but it’s also unusual. Perhaps we didn’t clean up well behind ourselves. I’m actually remembering reading something about how the non-Azure agents can cache things and I’m getting the vibe that this is the issue.

I say that yet the pipeline file already has clean: all under workspace which should very well be clearing any artifacts. What is going on? Well, clicking on the actual Job in the jobs area of the pipeline (drill down twice on “Job”) will tell you exactly which step failed and, in this case, it’s the “preparing build environment”. It looks like those permissions are not allowing for the build area to be cleaned. So let’s see if we can clean up after ourselves sufficiently.

root@markcentre:~# cd /home/vstsagent/
root@markcentre:/home/vstsagent# ls
agent  vsts-agent-linux-x64-2.196.1.tar.gz
root@markcentre:/home/vstsagent# cd agent
root@markcentre:/home/vstsagent/agent# ls
bin  config.sh  _diag  env.sh  externals  run-docker.sh  run.sh  runsvc.sh  svc.sh  _work
root@markcentre:/home/vstsagent/agent# cd _work
root@markcentre:/home/vstsagent/agent/_work# ls
1  2  node_modules  SourceRootMapping  _tasks  _temp  _tool
root@markcentre:/home/vstsagent/agent/_work# cd 1
root@markcentre:/home/vstsagent/agent/_work/1# ls
a  b  s  TestResults
root@markcentre:/home/vstsagent/agent/_work/1# cd ..
root@markcentre:/home/vstsagent/agent/_work# mv ./1 ..
root@markcentre:/home/vstsagent/agent/_work# ls
2  node_modules  SourceRootMapping  _tasks  _temp  _tool
root@markcentre:/home/vstsagent/agent/_work# mv ./2 ..

I moved the folders in question up just to make sure I had them if I still needed them. When those folders are gone the build executes just fine. It feels like there’s some contention as to the context of the file creation/modification. It would probably be best to just get rid of everything prior to finishing the task, but after deploying. Let’s take a look at that YAML pipeline file and see what we can do.

Investigating the pipeline

To be clear, this shouldn’t need to happen but we’re operating under specific circumstances. This is both the good part and the bad part about IT. In this situation I am not running the Azure build agent as root. To be even more specific–I’m not running a container in my build either however the AzureStaticWebApp task runs a file called launch-docker.sh to do the magic that it does. Even though I don’t need a container to build the site. It’s pretty cool that it runs a docker image with Oryx to actually do all the building of the image. This allows for a very modular approach where the code-building black box can be updated independently and I dig it.

This isn’t transparent to the end-user in the Azure DevOps pipeline, however, but it was interesting to learn regardless. Docker, by default, will write to disk as root which is where I’m running into permissions issues. It turns out that docker run has an argument for user. Perhaps this will work. I adjusted the launch-docker.sh to have that –user argument:

docker run --user "$(id -u):$(id -g)"\
    --env-file ./env.list \
    -v "$SWA_WORKING_DIR:$SWA_WORKSPACE_DIR" \
    "$SWA_DEPLOYMENT_CLIENT" \
    ./bin/staticsites/StaticSitesClient run

In using the id command it should, theoretically, Just Work. It did not. Popped off with an “unexpected error” once it was in the container. I’m getting the vibe that the container needs root for something that it does. That’s annoying.

Resolution or acceptance

It turns out that Oryx will throw an unspecified error any time the build script is run on a container with a non-root user specified in –user and that’s unfortunate. I’ll be submitting an enhancement request for that. I did work around this, though. The “straightforward” way is to simply just not build the application in the container but still use it to deploy the app. I haven’t actually drilled down into what that process is like so I’m still using the black box AzureStaticWebApp task. But I have an entire Linux box. The pipeline originally started with actually installs Hugo (like it would do on a container) but I’ve found out two things: since I’m not running the agent as root I simply can’t install or update Hugo as part of this process and I can do it with Homebrew. Well, I can install it with Homebrew, at least. So I did.

Aaaaand it didn’t work. ##[error]Bash exited with code '127'. is what I got. Turns out that when command line tasks run they run with –noprofile and –norc and that’s what Homebrew uses to set up your path (Homebrew sets everything up in the user’s folders and doesn’t require root). Ok cool no problem we just use the full path. That works but how do we get around the AzureStaticWebApp step? There’s a parameter called skip_app_build that will do it for us. For that step you can see something approaching the following in the output:

App Directory Location: '/public' was found.
No Api directory specified. Azure Functions will not be created.
Looking for event info
Skipping step to build /working_dir/public with Oryx
Either no Api directory was specified, or the specified directory was not found. Azure Functions will not be created.
Zipping App Artifacts
Done Zipping App Artifacts
Uploading build artifacts.
Finished Upload. Polling on deployment.

It’s the final pipeline 🎹

trigger:
- main

stages:
  - stage: 'GenerateHugo'
    displayName: 'Generate hugo website'
    jobs:
      - job:
        pool:
          name: Default

        workspace:
          #clean: all

        steps:
        - checkout: self
          displayName: 'Checkout repository including submodules'
          submodules: true  # true so Hugo theme submodule is checked out

        - task: CmdLine@2
          displayName: "Hugo build"
          #command line runs with --noprofile --norc and that's annoying
          inputs:
            script: '/home/vstsagent/.linuxbrew/bin/hugo'
        
        - task: AzureStaticWebApp@0
          condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
          inputs:
            skip_app_build: true 
            app_location: '/public'
            app_build_command: ''
            output_location: ''
            azure_static_web_apps_api_token: '$(TOKEN)'

If “The Final Countdown” is playing in your head then I have succeeded.

Lessons from the Pipeline

The real pipeline is the challenges we discovered along the way. You’ll note that the staging task is not present and that’s in the interest of clarity as well as because I don’t have a staging site up just yet. That’s going to tie in with the other stuff in the next post. This pipeline also will only work on a self-hosted agent. This might be what you need to do for reasons (in my case it was because I didn’t have that delicious free-tier grant) but it can really be a pain in the ass. It’s almost always better to KISS and this is entire post is an intentionally self-inflicted example of that. Not running the agent as root is really what made this difficult–not even because the build didn’t finish but because it couldn’t clear out the artifacts for the next build. Hugo, itself, doesn’t clear out that directory either so just rolling with it wouldn’t be advisable–you might end up using more storage than necessary. You could have a cron job continuously chowning the directory. You could spin up a container to clean the directory and then the container to deploy. You could do a lot of things but they’re all elements that add complexity. So keep it simple, stupid. If you don’t have an actual reason to run a self-hosted agent, don’t. Sometimes money is that reason and that’s ok. As long as there is a reason.

The real lesson, though, is to read better. Really read things. I read a few Issues on the Hugo Github about cleaning the output directory (and this makes total sense to me as well as other people) and they basically said “Hugo doesn’t clean those files. Figure it out, nerd.” I’m embellishing, but only slightly. I didn’t continue looking because I mistook confidence for fact. The Hugo Basic Usage page mentions a “flag” and yes, reader, there is indeed a --cleanDestinationDir flag. I genuinely don’t know how I missed that flag searching for ‘hugo clean’ but now that I’ve seen it it’s coming up ahead of the Issues pages. Thanks, search engines.

What’s happening now is that /public can’t be cleared when the repo checks out so I need to finally add that directory to my .gitignore. I have seen plenty of /public directories in repos for themes but I don’t really need to have it tracked in versioning (a statement I may very well regret at a later date). Just adding that to the build command (re-enabling the build in the AzureStaticWebApp task) and removing the workspace cleaning stuff. Since it’s a docker container that’s building the app I’m not worried about cruft in the OS. There are actually several ways that the repo gets cleaned and I’m just going to go through all of them and make sure they’re disabled. It didn’t work, regardless. I got a chunky new error: ##[warning]Unable move and reuse existing repository to required location.. I’m going to submit that enhancement request to be able to pass a script or something to the Oryx container so that we can clean up after ourselves if need be. We’ll see how snarky people get about it.

If you stuck with me for this roller coaster (or if you were yelling at me because you already thought of a solution), thanks! It’s been fun. Now on to part 2 where I’m gonna fix the site up a little more. Make it feel like home. 14 errors, 119 warnings and 0 suggestions

Hi, this post was checked with vale which is a content-aware linter. It was checked using the Microsoft style as well as some rules that I made. A summary of those results is below. More details as to how this was put together check out this post. This post had: 26 errors, 206 warnings and 98 suggestions For details on the linting of this post
 ./content/posts/setting-up-this-website.md
 1:1       suggestion  You averaged 1.24 complex       marktoso.Kiss            
                       words per sentence                                       
 10:26     suggestion  'is set' looks like passive     Microsoft.Passive        
                       voice.                                                   
 10:229    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 10:283    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 10:338    suggestion  Consider using 'idea' instead   Microsoft.ComplexWords   
                       of 'concept'.                                            
 10:356    warning     Consider removing 'fairly'.     Microsoft.Adverbs        
 10:401    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 16:4      suggestion  'The Roads Not Traveled'        Microsoft.Headings       
                       should use sentence-style                                
                       capitalization.                                          
 17:1      suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 17:62     warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 17:90     warning     Consider using 'before'         Microsoft.Wordiness      
                       instead of 'prior to'.                                   
 17:119    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 17:170    warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 17:289    suggestion  'are varied' looks like         Microsoft.Passive        
                       passive voice.                                           
 17:308    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 19:5      suggestion  'WSYWIG Content Management      Microsoft.Headings       
                       Systems' should use                                      
                       sentence-style capitalization.                           
 20:1      suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 20:4      warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 20:16     warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 20:24     warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 20:77     suggestion  'CMS' has no definition.        Microsoft.Acronyms       
 20:134    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 20:186    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 20:255    suggestion  'CMS' has no definition.        Microsoft.Acronyms       
 20:335    warning     Consider removing 'generally'.  Microsoft.Adverbs        
 20:373    error       Use 'they're' instead of 'They  Microsoft.Contractions   
                       are'.                                                    
 20:382    warning     Consider removing 'very'.       Microsoft.Adverbs        
 20:426    suggestion  Verify your use of 'allow'      Microsoft.Vocab          
                       with the A-Z word list.                                  
 20:465    warning     Consider removing 'quickly'.    Microsoft.Adverbs        
 20:477    warning     Consider removing 'easily'.     Microsoft.Adverbs        
 20:485    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 20:733    warning     Consider using 'all' instead    Microsoft.Wordiness      
                       of 'all of'.                                             
 20:771    warning     Consider removing 'very'.       Microsoft.Adverbs        
 20:791    suggestion  Consider using 'many' instead   Microsoft.ComplexWords   
                       of 'multiple'.                                           
 20:869    warning     Consider removing 'generally'.  Microsoft.Adverbs        
 22:35     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 22:251    suggestion  'be required' looks like        Microsoft.Passive        
                       passive voice.                                           
 22:359    suggestion  'CMS' has no definition.        Microsoft.Acronyms       
 22:408    warning     Consider removing 'terribly'.   Microsoft.Adverbs        
 22:454    warning     Consider removing               Microsoft.Adverbs        
                       'accidentally'.                                          
 22:531    warning     Consider removing               Microsoft.Adverbs        
                       'potentially'.                                           
 22:562    suggestion  'were made' looks like passive  Microsoft.Passive        
                       voice.                                                   
 22:655    suggestion  'CMS' has no definition.        Microsoft.Acronyms       
 22:757    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 22:966    warning     Consider removing 'generally'.  Microsoft.Adverbs        
 22:982    error       Use 'they're' instead of 'They  Microsoft.Contractions   
                       are'.                                                    
 22:1083   suggestion  Consider using 'part' instead   Microsoft.ComplexWords   
                       of 'component'.                                          
 22:1099   suggestion  Verify your use of              Microsoft.Vocab          
                       'accessible' with the A-Z word                           
                       list.                                                    
 22:1138   warning     Consider removing 'generally'.  Microsoft.Adverbs        
 24:5      suggestion  'Hosted Web Services'           Microsoft.Headings       
                       should use sentence-style                                
                       capitalization.                                          
 25:35     warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 25:35     error       Use 'we've' instead of 'we      Microsoft.Contractions   
                       have'.                                                   
 25:68     error       More than 3 commas!             marktoso.TresComas       
 25:78     warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 25:186    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 25:302    suggestion  'be mentioned' looks like       Microsoft.Passive        
                       passive voice.                                           
 25:405    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 25:466    warning     Consider removing 'very'.       Microsoft.Adverbs        
 25:471    warning     Consider removing 'easily'.     Microsoft.Adverbs        
 25:516    suggestion  Verify your use of 'as well     Microsoft.Vocab          
                       as' with the A-Z word list.                              
 27:1      suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 27:46     suggestion  'SFTP' has no definition.       Microsoft.Acronyms       
 27:52     suggestion  'FTP' has no definition.        Microsoft.Acronyms       
 27:100    warning     ' previously-' doesn't need a   Microsoft.Hyphens        
                       hyphen.                                                  
 27:101    suggestion  Consider using 'before'         Microsoft.ComplexWords   
                       instead of 'previously'.                                 
 27:134    suggestion  'FTP' has no definition.        Microsoft.Acronyms       
 27:173    warning     Consider removing 'generally'.  Microsoft.Adverbs        
 27:217    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 27:434    suggestion  'CMS' has no definition.        Microsoft.Acronyms       
 29:4      suggestion  'Enter the Modern Static Site'  Microsoft.Headings       
                       should use sentence-style                                
                       capitalization.                                          
 30:20     error       Use 'it's' instead of 'it is'.  Microsoft.Contractions   
 30:78     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 30:184    warning     Consider removing 'really'.     Microsoft.Adverbs        
 30:222    error       More than 3 commas!             marktoso.TresComas       
 30:700    suggestion  Verify your use of 'allow'      Microsoft.Vocab          
                       with the A-Z word list.                                  
 30:793    warning     Consider removing 'heavily'.    Microsoft.Adverbs        
 30:867    warning     Consider removing 'generally'.  Microsoft.Adverbs        
 32:80     suggestion  'GCP' has no definition.        Microsoft.Acronyms       
 32:85     suggestion  'AWS' has no definition.        Microsoft.Acronyms       
 32:194    suggestion  Consider using 'give' or        Microsoft.ComplexWords   
                       'offer' instead of 'provide'.                            
 32:283    suggestion  Consider using 'give' or        Microsoft.ComplexWords   
                       'offer' instead of 'provide'.                            
 32:383    error       Use 'for example' instead of    Microsoft.Foreign        
                       'e.g.'.                                                  
 32:393    suggestion  'is built' looks like passive   Microsoft.Passive        
                       voice.                                                   
 32:485    error       Use 'that's' instead of 'that   Microsoft.Contractions   
                       is'.                                                     
 32:490    suggestion  'is geared' looks like passive  Microsoft.Passive        
                       voice.                                                   
 34:4      suggestion  'Deploying a Hugo Site          Microsoft.Headings       
                       on Azure' should use                                     
                       sentence-style capitalization.                           
 35:40     warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 35:131    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 35:148    warning     Consider using 'some' instead   Microsoft.Wordiness      
                       of 'some of the'.                                        
 35:187    warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 38:350    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 38:538    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 41:150    warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 41:224    warning     Consider removing 'very'.       Microsoft.Adverbs        
 48:14     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 48:81     suggestion  'are interested' looks like     Microsoft.Passive        
                       passive voice.                                           
 48:215    suggestion  'are taken' looks like passive  Microsoft.Passive        
                       voice.                                                   
 66:5      suggestion  'Setting up Azure DevOps'       Microsoft.Headings       
                       should use sentence-style                                
                       capitalization.                                          
 67:58     suggestion  Verify your use of 'ensure'     Microsoft.Vocab          
                       with the A-Z word list.                                  
 69:59     suggestion  'be greeted' looks like         Microsoft.Passive        
                       passive voice.                                           
 69:96     warning     Consider removing 'really'.     Microsoft.Adverbs        
 69:144    suggestion  Consider using 'give' or        Microsoft.ComplexWords   
                       'offer' instead of 'provide'.                            
 69:276    warning     For a general audience, use     Microsoft.GeneralURL     
                       'address' rather than 'URL'.                             
 69:403    error       Punctuation should be inside    Microsoft.Quotes         
                       the quotes.                                              
 69:419    error       Punctuation should be inside    Microsoft.Quotes         
                       the quotes.                                              
 74:436    warning     Consider removing 'very'.       Microsoft.Adverbs        
 78:1      error       Use 'we're' instead of 'we      Microsoft.Contractions   
                       are'.                                                    
 78:244    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 78:342    warning     Consider removing 'very'.       Microsoft.Adverbs        
 78:375    warning     Consider removing 'extremely'.  Microsoft.Adverbs        
 79:47     warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 80:260    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 83:29     warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 83:118    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 83:258    warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'our'.                                                   
 85:135    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 85:153    warning     Consider removing 'really'.     Microsoft.Adverbs        
 85:168    suggestion  'was tied' looks like passive   Microsoft.Passive        
                       voice.                                                   
 85:186    suggestion  'WNYC' has no definition.       Microsoft.Acronyms       
 85:216    warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 85:229    suggestion  'been forked' looks like        Microsoft.Passive        
                       passive voice.                                           
 85:269    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 87:1      warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 87:127    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 87:167    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 87:177    warning     Consider using 'whether'        Microsoft.Wordiness      
                       instead of 'whether or not'.                             
 87:205    warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 89:39     warning     In general, don't use an        Microsoft.Ellipses       
                       ellipsis.                                                
 89:77     warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 89:120    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 89:359    warning     Consider removing 'very'.       Microsoft.Adverbs        
 135:3     warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 135:233   suggestion  Consider using 'equal' instead  Microsoft.ComplexWords   
                       of 'equivalent'.                                         
 135:356   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 135:397   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 135:469   error       Use 'it's' instead of 'it is'.  Microsoft.Contractions   
 135:481   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 135:586   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 135:746   warning     Consider removing 'terribly'.   Microsoft.Adverbs        
 135:789   error       Use 'it's' instead of 'it is'.  Microsoft.Contractions   
 135:800   error       Use 'it's' instead of 'it is'.  Microsoft.Contractions   
 135:839   suggestion  'be addressed' looks like       Microsoft.Passive        
                       passive voice.                                           
 137:13    suggestion  'LATER' has no definition.      Microsoft.Acronyms       
 138:18    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 138:51    warning     In most cases, use 'from' or    Microsoft.Ranges         
                       'through' to describe a range                            
                       of numbers.                                              
 138:51    error       Use an en dash in a range of    Microsoft.RangeFormat    
                       numbers.                                                 
 138:83    warning     Consider removing 'very'.       Microsoft.Adverbs        
 138:109   error       Use 'that's' instead of 'that   Microsoft.Contractions   
                       is'.                                                     
 138:144   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 138:231   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 138:268   warning     Consider removing 'very'.       Microsoft.Adverbs        
 140:1     warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 140:14    warning     Consider removing 'very'.       Microsoft.Adverbs        
 140:256   warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 140:294   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 140:335   error       Use 'it's' instead of 'It is'.  Microsoft.Contractions   
 140:341   warning     Consider removing 'very'.       Microsoft.Adverbs        
 140:356   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 142:51    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 142:107   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 142:151   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 142:348   warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 142:355   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 142:391   warning     Consider removing 'Seriously'.  Microsoft.Adverbs        
 142:407   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 142:415   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 144:30    warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 145:2     suggestion  'ONE' has no definition.        Microsoft.Acronyms       
 145:6     suggestion  'DAY' has no definition.        Microsoft.Acronyms       
 145:10    suggestion  'LATER' has no definition.      Microsoft.Acronyms       
 145:21    warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 145:56    warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 145:62    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 145:113   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 145:198   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 145:245   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 145:391   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 145:469   error       Use 'they're' instead of 'they  Microsoft.Contractions   
                       are'.                                                    
 145:521   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 155:71    warning     Prefer 'YMMV' over 'ymmv'.      marktoso.Substitue       
 155:205   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 155:367   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'Agent'.                                 
 155:428   warning     In general, don't use an        Microsoft.Ellipses       
                       ellipsis.                                                
 155:447   warning     Consider removing 'extremely'.  Microsoft.Adverbs        
 155:488   suggestion  'PAT' has no definition.        Microsoft.Acronyms       
 155:557   suggestion  Verify your use of 'ensure'     Microsoft.Vocab          
                       with the A-Z word list.                                  
 155:640   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 155:694   suggestion  'PAT' has no definition.        Microsoft.Acronyms       
 160:84    warning     Consider removing 'really'.     Microsoft.Adverbs        
 160:113   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 160:212   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 160:263   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 160:430   suggestion  Verify your use of 'against'    Microsoft.Vocab          
                       with the A-Z word list.                                  
 162:1     warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 162:1     error       Use 'we're' instead of 'We      Microsoft.Contractions   
                       are'.                                                    
 162:79    warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 162:79    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 162:128   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 162:247   error       Use 'isn't' instead of 'is      Microsoft.Contractions   
                       not'.                                                    
 162:347   warning     Consider using 'if' instead of  Microsoft.Wordiness      
                       'in the event that'.                                     
 162:421   suggestion  'be adjusted' looks like        Microsoft.Passive        
                       passive voice.                                           
 162:503   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 162:528   error       Use 'can't' instead of          Microsoft.Contractions   
                       'cannot'.                                                
 162:540   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 162:592   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 164:78    suggestion  Verify your use of 'Ensure'     Microsoft.Vocab          
                       with the A-Z word list.                                  
 164:119   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 164:208   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 164:243   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 164:253   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 164:335   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 172:109   suggestion  Consider using 'let' instead    Microsoft.ComplexWords   
                       of 'permit'.                                             
 172:172   suggestion  Verify your use of 'ensure'     Microsoft.Vocab          
                       with the A-Z word list.                                  
 174:38    warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 174:144   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 174:275   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 189:12    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 189:103   warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'Let's'.                                                 
 191:71    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 191:113   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 191:213   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 191:274   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 191:313   warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'our'.                                                   
 191:346   warning     For a general audience, use     Microsoft.GeneralURL     
                       'address' rather than 'URL'.                             
 194:30    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 194:135   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 194:172   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 194:246   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 194:391   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 194:391   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 194:426   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 194:449   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 194:494   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 194:530   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 194:544   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 199:3     warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 204:1     warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'Let's'.                                                 
 222:146   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 222:188   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 222:283   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 224:1     warning     Use first person (such as 'I    Microsoft.FirstPerson    
                       ') sparingly.                                            
 224:90    warning     Consider removing 'very'.       Microsoft.Adverbs        
 224:127   error       Use 'what's' instead of 'What   Microsoft.Contractions   
                       is'.                                                     
 224:145   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 224:307   error       Punctuation should be inside    Microsoft.Quotes         
                       the quotes.                                              
 224:370   error       Use 'aren't' instead of 'are    Microsoft.Contractions   
                       not'.                                                    
 224:409   suggestion  'be cleaned' looks like         Microsoft.Passive        
                       passive voice.                                           
 224:424   warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'let's'.                                                 
 224:437   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 244:1     warning     Use first person (such as 'I    Microsoft.FirstPerson    
                       ') sparingly.                                            
 244:53    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 244:67    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 244:108   suggestion  'are gone' looks like passive   Microsoft.Passive        
                       voice.                                                   
 244:294   warning     Consider using 'before'         Microsoft.Wordiness      
                       instead of 'prior to'.                                   
 244:346   warning     Try to avoid using              Microsoft.We             
                       first-person plural like                                 
                       'Let's'.                                                 
 244:404   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 247:1     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 247:50    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 247:167   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 247:203   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 247:244   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 247:275   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 247:405   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 247:593   suggestion  Verify your use of 'allows'     Microsoft.Vocab          
                       with the A-Z word list.                                  
 247:606   warning     Consider removing 'very'.       Microsoft.Adverbs        
 247:666   suggestion  'be updated' looks like         Microsoft.Passive        
                       passive voice.                                           
 247:694   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 249:185   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 249:363   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 257:67    error       Use 'didn't' instead of 'did    Microsoft.Contractions   
                       not'.                                                    
 257:144   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 260:1     suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 260:82    suggestion  'is run' looks like passive     Microsoft.Passive        
                       voice.                                                   
 260:253   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 260:442   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 260:499   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 260:659   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 260:679   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 260:692   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 260:758   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 260:855   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 262:72    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 262:80    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 262:307   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 262:356   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 262:462   warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'us'.                           
 311:54    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 313:4     suggestion  'Lessons from the Pipeline'     Microsoft.Headings       
                       should use sentence-style                                
                       capitalization.                                          
 314:37    warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 314:66    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 314:100   error       Use 'isn't' instead of 'is      Microsoft.Contractions   
                       not'.                                                    
 314:153   suggestion  Verify your use of 'as well     Microsoft.Vocab          
                       as' with the A-Z word list.                              
 314:171   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 314:328   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 314:335   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 314:385   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 314:407   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 314:465   warning     Consider removing 'really'.     Microsoft.Adverbs        
 314:524   suggestion  'KISS' has no definition.       Microsoft.Acronyms       
 314:698   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 314:714   warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 314:731   warning     Consider removing 'really'.     Microsoft.Adverbs        
 314:1336  warning     Prefer 'personal digital        Microsoft.Terms          
                       assistant' over 'agent'.                                 
 316:45    warning     Consider removing 'Really'.     Microsoft.Adverbs        
 316:67    suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 316:173   warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 316:176   suggestion  Verify your use of 'as well     Microsoft.Vocab          
                       as' with the A-Z word list.                              
 316:280   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 316:350   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 316:639   suggestion  'is indeed' looks like passive  Microsoft.Passive        
                       voice.                                                   
 316:707   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 318:46    suggestion  'be cleared' looks like         Microsoft.Passive        
                       passive voice.                                           
 318:84    warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 318:125   warning     Use first person (such as       Microsoft.FirstPerson    
                       'my') sparingly.                                         
 318:140   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 318:205   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 318:214   warning     Consider removing 'really'.     Microsoft.Adverbs        
 318:271   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 318:278   warning     Consider removing 'very'.       Microsoft.Adverbs        
 318:295   warning     Consider using 'later' instead  Microsoft.Wordiness      
                       of 'at a later date'.                                    
 318:503   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 318:757   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 318:786   warning     Consider using 'all' instead    Microsoft.Wordiness      
                       of 'all of'.                                             
 318:820   suggestion  Don't use language (such        Microsoft.Accessibility  
                       as 'disabled') that defines                              
                       people by their disability.                              
 318:962   suggestion  Try to keep sentences short (<  Microsoft.SentenceLength 
                       30 words).                                               
 318:962   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 318:1078  warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'we'.                           
 318:1122  warning     Try to avoid using              Microsoft.We             
                       first-person plural like 'We'.                           
 320:19    warning     Use first person (such as       Microsoft.FirstPerson    
                       'me') sparingly.                                         
 320:166   warning     Use first person (such as       Microsoft.FirstPerson    
                       'I'm') sparingly.                                        
 324:40    suggestion  'was checked' looks like        Microsoft.Passive        
                       passive voice.                                           
 324:146   suggestion  'was checked' looks like        Microsoft.Passive        
                       passive voice.                                           
 324:184   suggestion  Verify your use of 'as well     Microsoft.Vocab          
                       as' with the A-Z word list.                              
 324:210   warning     Use first person (such as ' I   Microsoft.FirstPerson    
                       ') sparingly.                                            
 324:284   suggestion  'was put' looks like passive    Microsoft.Passive        
                       voice.                                                   

26 errors, 207 warnings and 102 suggestions in 1 file.