Skip to content

Set up deployment pipeline

Set up a deployment pipeline that builds your static website once and deploys it to S3/CloudFront across environments.

Before you begin

  • Set up CloudFront static website infrastructure.
  • Have a GitHub repository in the oslokommune organization for your application (not your IaC repo). We recommend that you use your team name as prefix.

Step 1: Protect your default branch

Your repository automatically inherits branch rulesets from the GitHub organization when you set a custom property. Go to Settings > Custom properties and set gp-repository-type to app.

After setting the custom property, verify that Settings > Rulesets shows rules inherited from the organization.

Step 2: Create a GitHub Actions environment for production

This restricts production deployments to the default branch.

  1. Go to Settings > Environments > New environment
  2. Set the name to match your production environment:
    • For an application repo: <environment> (e.g., pirates-prod)
    • For an application in a monorepo <environment>-<app-name> (e.g., pirates-prod-zebra)
  3. Under Deployment branches and tags, select Selected branches and add your default branch (main or master)

Manual approval

To enable manual approval, open your GitHub Actions environment for production:

  1. Set Required reviewers to your GitHub team
  2. Click Save protection rules

Step 3: Request CI/CD access

Message Utviklerflyt on Slack (#utviklerflyt-support) to add your application repository to their centralized configuration:

Hei! Kan dere gi <repo-app> nødvendige tilganger for CI/CD?

Info

To increase the level of self-service, we're currently working on removing the need for this step.

Step 4: Add configuration files

Create a new branch and add the following configuration files.

Step 4.1: Add .gp.cicd.json

The configuration differs depending on your repository type:

  • Application repo — the repository contains code for a single application, while the associated infrastructure lives in a separate IaC repository (e.g., pirates-iac).
  • Application monorepo — the repository contains code for multiple applications, while the associated infrastructure lives in a separate IaC repository (e.g., pirates-iac).

Download .gp.cicd.json:

gh api repos/oslokommune/golden-path-templates/contents/templates/gh-cicd-app/.gp.cicd.json \
  --jq '.content' | base64 -d > .gp.cicd.json

Update these values (many of which can be found in common-config.yml in your infrastructure repository):

Field Description Example
<team-name> Your team name pirates
<repo-iac> Infrastructure-as-code repository name pirates-iac
<dev-aws-account-id> AWS account ID for dev 123456789012
<prod-aws-account-id> AWS account ID for prod 987654321098
<dev-environment-name> Name of your dev environment pirates-dev
<prod-environment-name> Name of your prod environment pirates-prod
<aws-region> Your AWS region eu-west-1

Download .gp.cicd.json:

gh api repos/oslokommune/golden-path-templates/contents/templates/gh-cicd-app-monorepo/.gp.cicd.json \
  --jq '.content' | base64 -d > .gp.cicd.json

Update these values (many of which can be found in common-config.yml in your infrastructure repository):

Field Description Example
<team-name> Your team name pirates
<repo-iac> Infrastructure-as-code repository name pirates-iac
<dev-aws-account-id> AWS account ID for dev 123456789012
<prod-aws-account-id> AWS account ID for prod 987654321098
<dev-environment-name> Name of your dev environment pirates-dev
<prod-environment-name> Name of your prod environment pirates-prod
<aws-region> Your AWS region eu-west-1

Step 4.2: Add CODEOWNERS

Add a CODEOWNERS file to define who owns the repository and approves PRs:

repo-app/.github/CODEOWNERS
* @oslokommune/<github-team-name>
Field Description Example
<github-team-name> The name of your GitHub team utviklerflyt

Step 4.3: Add Renovate configuration

Download renovate.json5 to the repository root:

gh api repos/oslokommune/golden-path-templates/contents/templates/gh-cicd-app/renovate.json5 \
  --jq '.content' | base64 -d > renovate.json5

What is Renovate?

Renovate automatically creates pull requests to keep your dependencies up to date. Think of it as a better Dependabot. Learn more in the Renovate reference documentation.

Step 5: Add the deployment workflow

Download the zebra deployment workflow as a starting point and save it to .github/workflows/<app-name>_deployment.yml.

Address the TODO comments in the workflow. The main adaptation is in the build-and-upload-artifact job, where you customize the build and test steps to match your application.

Build once deploy many

The deployment pipeline is designed to build, upload and promote the exact same immutable artifact across environments ("build once, deploy many").

For static websites where configuration typically differs per environment, see how zebra handles environment configuration.

Post-deployment testing

The deployment pipeline contains a job test-dev and test-prod that runs after deployment to development and production, respectively. Feel free to add more tests to these jobs to validate the behavior of your running application in AWS after a deployment (e.g., smoke tests, end-to-end tests, etc.).

Step 6: Create a pull request

Push the branch and create a pull request.

Verify that the build job succeeds and that no deployment occurs.

Step 7: Merge and deploy

  1. Merge the pull request.
  2. The workflow deploys to your dev environment automatically. Verify the site is accessible by checking that the Test webapp job succeeds — a green check means the job curled your dev URL and got a response.
  3. Approve the production deployment when prompted. Verify that the production site is accessible.