Continuous Deployment of Wyam generated site

Published on Thursday, August 22, 2019

This is 3rd post in my series about experience with Wyam. This post is about setting up continuous deployment of static web site generated by Wyam. I am using Azure DevOps for deployment.

Define Azure Pipeline

At first it is needed to define build pipeline. This is done by adding file named azure-pipelines.yml into the repository with Wyam web site. The azure-pipelines.yml is YAML file that defines Azure DevOps pipeline. The file must follow YAML schema for Azure Pipelines. It may be overwhelming at first, so let's look at it step by step.

First part defines that pipeline should be executed on any push into master branch. And it should not be executed, when a pull request is created. This policy works for me as I am the only author of the website and follows trunk-based development. However, if your team is bigger or you maintain open-source website with contributions, then you may need to setup some pull-request policies.

- master

pr: none

Then job part is included. The pipeline contains single job. The job is executed on Windows Server agent with Visual Studio 2019. It's possible to find list of all avilable Azure DevOps hosted agents. The job also cleans all build directories before start. This is not necessary, because hosted agents are cleaned for every build. I just have this preference from using on-premise build agents.

- job: DuracellkoWebSite
  displayName: Duracellko.WebSite

    vmImage: windows-2019
    clean: all

Last and the most important part of the YAML file are job steps. First step installs Wyam dotnet global tool. Basically it executes following command: dotnet tool install -g Wyam.Tool

  - task: DotNetCoreCLI@2
    displayName: Install Wyam
      command: custom
      custom: tool
      arguments: install -g Wyam.Tool

Next step is to generate static website. This is simple, assuming that the website is in root folder of the repository. Just run wyam command. It generates static website in output folder.

  - script: wyam

Next 2 steps ZIP the website (output folder) and publish it into build artifacts.

  - task: ArchiveFiles@2
    displayName: ZIP output
      archiveType: zip
      rootFolderOrFile: $(Build.SourcesDirectory)/output
      archiveFile: $(Build.StagingDirectory)/
      includeRootFolder: false
      replaceExistingArchive: true
  - task: PublishBuildArtifacts@1
    displayName: Publish artifact
      PathtoPublish: $(Build.StagingDirectory)
      ArtifactName: web

And last step uploads the website to server using FTPS, where it is hosted by web hosting provider. YAML file does not contain connection details for FTP server. Surely no one wants to publish this secret information in public Git repository. It just refers to server endpoint that contains this information. The endpoint will be created later.

  - task: FtpUpload@2
    displayName: Upload to
      serverEndpoint: ''
      rootDirectory: $(Build.SourcesDirectory)/output
      remoteDirectory: /
      preservePaths: true
      clean: false
      cleanContents: true
      trustSSL: true

The step deletes all files and subfolders from root folder of FTP site. Then it uploads content of output folder including subfolders.

Full azure-pipelines.yml can be found in GitHub repository.

Setup Azure DevOps project

When azure-pipelines.yml file is in the repository, it's time to execute the deployment. I assume, you have already setup Azure DevOps organization. If not, you should start by setting up new Azure DevOps account for free. Then it's neccessary to create new Azure DevOps project. Also existing project can be used. At Azure DevOps organization home page click New project. Enter name of the project (e.g. My static web). In advanced options select following settings:

  • Version control: Git
  • Work item process: Basic

Create Azure DevOps project

When project is created, open project settings. You can disable all Azure DevOps services except Pipelines. They won't be needed.

Azure DevOps project services

Then project needs to connect to GitHub repository with the Wyam website. Open Service connections settings and click Create service connection. Select GitHub service and click Next.

New GitHub Service connection

Enter connection name (e.g. MyGitHub). And click Authorize. Assuming you are logged into your GitHub account, the Azure DevOps project gets authorized to access your GitHub account. Click OK to save the Service Connection

GitHub Service connection

Then it's needed to create a connection to FTPS server, where the website should be uploaded. Again click New service connection. Select Generic and click Next.

New Generic Service connection

Enter connection details to your FTP server:

  • ServerURL: URL of FTP server (e.g. ftps://
  • Username: Username for connecting to the FTP server.
  • Password: Password for connecting to the FTP server.
  • Service connection name: Name of server endpoint that you specified in the YAML file (e.g.

GitHub Service connection

Now there should be 2 service connections.

Azure DevOps Service connections

And finally it's possible to start build and deployment. From left menu open Pipelines. Then click Create Pipeline. Select GitHub repository.

Azure DevOps Pipeline source code

Then select repository with the Wyam website. azure-pipelines.yml file is found, so you can simply start deployment by clicking Run.

Azure DevOps Pipeline - Review

If everything was set correctly then build should finish successfully.

Azure DevOps - Successful build

Website should be deployed to the webhosting server. And it should be possible to download it from Build artifacts.

Azure DevOps - Build artifacts

From now on, whenever you push any change into matser branch, the website is generated and uploaded to the webserver.

PS: Be aware that website is generated on Microsoft hosted agent that has configured UTC time zone. It means that a fresh new blog post may not be published because of different time zone. For example, you are in New Zealand time zone (UTC+12). It's 8:00 in morning on August 21st, you did final review of the blog post and set publish date to August 21st. And push everything to master branch. Then build agent builds the website, but its local time is August 20th 19:00. And Wyam generator works the way that blog posts with publish date after this time are not published. So the newest post with publish date August 21st simply does not get out.

There is already Wyam enhancement suggestion to make time of generating Wyam website configurable. This way, it would be possible to override local time zone of build agents.