Setting up the Hugo website generator in CodePipeline

Construction Yard

Setting up the Hugo website generator in CodePipeline

Last time, we used CDK to host a static website in AWS. Today we’re going to look at adding a static site generator to our pipeline so that we don’t have to create all of our pages by hand.

We’ve found the Hugo static site generator to be simple and effective, so we’ll use it for this example, but the steps should apply to any similar tool.

First, we’ll need a buildspec. This needs an install phase to set up the generator tool in the pipeline runner, and a build phase to execute it. It serves no practical purpose to upload the source files to S3, so we’ll only export the generated assets as artifacts. With Hugo, this will be the contents of the public/ directory.

We also have Hugo modules in the project, so we’ll need to ensure those are installed with hugo mod get, and since Hugo is written in Go, we’ll need an appropriate version of the Go runtime.

BuildSpec.fromObject({
  version: '0.2',
  phases: {
    install: {
      'runtime-versions': {
        golang: '1.20',
      },
      commands: [
        'echo "Installing Hugo"',
        'wget -O hugo.tar.gz https://github.com/gohugoio/hugo/releases/download/v0.121.2/hugo_0.121.2_Linux-64bit.tar.gz',
        'tar -zxvf hugo.tar.gz',
        'mv hugo /usr/local/bin/hugo',
        'hugo mod get -u',
      ],
    },
    build: {
      commands: [
        'echo "Building Hugo Site"',
        'hugo',
      ],
    },
  },
  artifacts: {
    'base-directory': 'public',
    files: ['**/*'],
  },
})

Putting this into our existing pipeline looks like this:

const sourceCodeArtifact     = new Artifact(`${siteName}-source-artifact`);
const compiledAssetsArtifact = new Artifact(`${siteName}-compiled-assets-artifact`);

return new Pipeline(this, 'DeploymentPipeline', {
  pipelineName: `${siteName}-deployment-pipeline`,
  crossAccountKeys: false,
  stages: [
    {
      stageName: 'Source',
      actions: [
        new CodeCommitSourceAction({
          actionName: 'Source',
          output: sourceCodeArtifact,
          repository,
          trigger: CodeCommitTrigger.EVENTS,
        }),
      ],
    },
    {
      stageName: 'Build',
      actions: [
        new CodeBuildAction({
          actionName: 'Build',
          input: sourceCodeArtifact,
          project: new PipelineProject(this, `${siteName}-BuildProject`, {
            environment: {
              buildImage: LinuxBuildImage.STANDARD_7_0,
            },
            buildSpec: BuildSpec.fromObject({
              version: '0.2',
              phases: {
                install: {
                  'runtime-versions': {
                    golang: '1.20',
                  },
                  commands: [
                    'echo "Installing Hugo"',
                    'wget -O hugo.tar.gz https://github.com/gohugoio/hugo/releases/download/v0.121.2/hugo_0.121.2_Linux-64bit.tar.gz',
                    'tar -zxvf hugo.tar.gz',
                    'mv hugo /usr/local/bin/hugo',
                    'hugo mod get -u',
                  ],
                },
                build: {
                  commands: [
                    'echo "Building Hugo Site"',
                    'hugo',
                  ],
                },
              },
              artifacts: {
                'base-directory': 'public',
                files: ['**/*'],
              },
            }),
          }),
          type: CodeBuildActionType.BUILD,
          outputs: [compiledAssetsArtifact],
        }),
      ],
    },
    {
      stageName: 'Deploy',
      actions: [
        new S3DeployAction({
          actionName: 'Deploy',
          bucket: siteBucket,
          input: compiledAssetsArtifact,
        }),
      ],
    },
  ],
});

The final thing to note is the environment property that sets the base image used by the pipeline runner. Without this, AWS will default to STANDARD_1, which is very outdated and will likely cause issues when trying to install tools. A list of available images can be found here.

Now, when we push updates to our website repo, the pipeline will trigger, which will build the website with Hugo and send the updated assets to S3.


See also