Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a staging workflow #1

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

github-learning-lab[bot]
Copy link

Welcome to the course!

We'll learn how to create a workflow that enables Continuous Delivery. You'll:

  • create a workflow to deploy to staging based on a label
  • create a workflow to deploy to production based on merging to main

Before you start, you should be familiar with GitHub and Continuous Integration. If you aren't sure where to start, you may want to check out these two Learning Lab courses:

What is Continuous Delivery?

Martin Fowler defined Continuous Delivery very simply in a 2013 post as follows:

Continuous Delivery is a software development discipline where you build software in such a way that the software can be released to production at any time.

A lot of things go into delivering "continuously". These things can range from culture and behavior to specific automation. In this course, we're going to focus on deployment automation.

Setting up environments and kicking off deployments

Automation works at its best when a set of triggers work harmoniously to set up and deploy to target environments. Engineers at many companies, like at GitHub, typically use a ChatOps command as a trigger. The trigger itself isn't incredibly important.

In our use case, we'll use labels as triggers for multiple tasks:

  • When someone applies a "spin up environment" label to a pull request, that'll tell GitHub Actions that we'd like to set up our resources on an Azure environment.
  • When someone applies a "stage" label to a pull request, that'll be our indicator that we'd like to deploy our application to a staging environment.
  • When someone applies a "destroy environment" label to a pull request, we'll tear down any resources that are running on our Azure account.

For now, we'll focus on staging. We'll spin up and destroy our environment in a later step.

Step 1: Configure a trigger based on labels

In a GitHub Actions workflow, the on step defines what causes the workflow to run. In this case, we want the workflow to run whenever a label is applied to the pull request.

⌨️ Activity: Configure the workflow trigger based on a label being added

  1. Edit the deploy-staging.yml file on this branch, or use this quick link (We recommend opening the quick link in another tab)
  2. Change the name of the directory CHANGETHIS to workflows, so the title of this file with the path is .github/workflows/deploy-staging.yml. If you're working on the GitHub.com user interface, see the suggestion below for how to rename.
  3. Edit the contents of this file to trigger a job called build on a label
Changing the name of a directory

If you're working locally, rename your file or drag-and-drop the file into the proper directory as you'd normally do. If you're working on GitHub.com, you can change the name of a directory by changing its filename and using the Backspace key until you reach the directory, as follows:

  1. In the file name field, click in front of the first character in the file name
  2. Press Backspace or Delete on your keyboard until you see the path you want to keep. You can continue to press Backspace even if the text box with the file name is empty.
  3. Enter the new name for your directory.
  4. Enter / to let GitHub know this should be a new directory.

Your resulting file should be in .github/workflows/deploy-staging.yml and it should look like this:

name: Stage the app

on: 
  pull_request:
    types: [labeled]

jobs:
  build:
    runs-on: ubuntu-latest

I'll respond when you push a commit on this branch.

@github-learning-lab
Copy link
Author

It looks like you took an action I didn't expect.

I expected you to commit the file .github/workflows/deploy-staging.yml and a [labeled] trigger on the staging-workflow branch. Please try that to continue!

correct typo in pull-request
@github-learning-lab
Copy link
Author

Job conditionals

GitHub Actions features powerful controls for when to execute jobs and the steps within them. One of these controls is if, which allows you run a job only when a specific condition is met. See jobs.<job_id>.if in Workflow syntax for GitHub Actions for more information.

Using information within GitHub

Workflows are part of the GitHub ecosystem, so each workflow run gives you access to a rich set of data that you can use to take fine-grained control.

We'd like to run our workflow on a specific label name, suppose that it's peacock. We can run the workflow based on that label name with the following single line that packs a punch: if: contains(github.event.pull_request.labels.*.name, 'peacock'). Here's how it works:

  • if: is the conditional that will decide if the job will run
  • contains() is a function that allows us to determine if a value like say, a label named "peacock", is contained within a set of values like say, a label array ["bug", "stage", "peacock", "feature request"]
  • github.event.pull_request.labels is specifically accessing the set of labels that triggered the workflow to run. It does this by accessing the github object, and the pull_request event that triggered the workflow.
  • github.event.pull_request.labels.*.name uses object filters to filter out all information about the labels, like their color or description, and lets us focus on just the label names.

Step 2: Trigger a job on specific labels

Let's put all this together to run our job only when a labeled named "stage" is applied to the pull request.

⌨️ Activity: Add a conditional to select from labels

  1. Edit the deploy-staging.yml file on this branch, or use this quick link (We recommend opening the quick link in another tab)
  2. Edit the contents of the file to add a block for environment variables before your jobs, as follows.
    env:
      DOCKER_IMAGE_NAME: petetian-azure-ttt
      IMAGE_REGISTRY_URL: docker.pkg.github.com
      #################################################
      ### USER PROVIDED VALUES ARE REQUIRED BELOW   ###
      #################################################
      #################################################
      ### REPLACE USERNAME WITH GH USERNAME         ###
      AZURE_WEBAPP_NAME: petetian-ttt-app
      #################################################
  3. Edit the contents of the file to add a conditional that filters the build job using a label called "stage".

Your results should look like this:

name: Stage the app

on: 
  pull_request:
    types: [labeled]

env:
  DOCKER_IMAGE_NAME: petetian-azure-ttt
  IMAGE_REGISTRY_URL: docker.pkg.github.com
  #################################################
  ### USER PROVIDED VALUES ARE REQUIRED BELOW   ###
  #################################################
  #################################################
  ### REPLACE USERNAME WITH GH USERNAME         ###
  AZURE_WEBAPP_NAME: petetian-ttt-app
  #################################################

jobs:
  build:
    runs-on: ubuntu-latest

    if: contains(github.event.pull_request.labels.*.name, 'stage')

I'll respond when you push a commit on this branch.

add conditions and env
@github-learning-lab
Copy link
Author

Workflow steps

So far, the workflow knows what the trigger is and what environment to run in. But, what exactly is supposed to run? The "steps" section of this workflow specifies actions and scripts to be run in the Ubuntu environment when new labels are added.

Step 3: Set up the environment for your app

We won't be going into detail on the steps of this workflow, but it would be a good idea to become familiar with the actions we're using. They are:

The course Using GitHub Actions for CI also teaches how to use most of these actions in details.

⌨️ Activity: Store your credentials in GitHub secrets and finish setting up your workflow

  1. In a new tab, create an Azure account if you don't already have one. If your Azure account is created through work, you may encounter issues accessing the necessary resources -- we recommend creating a new account for personal use and for this course.

    Note: You may need a credit card to create an Azure account. If you're a student, you may also be able to take advantage of the Student Developer Pack for access to Azure. If you'd like to continue with the course without an Azure account, Learning Lab will still respond, but none of the deployments will work.

  2. Create a new subscription in the Azure Portal.

    Note: your subscription must be configured "Pay as you go" which will require you to enter billing information. This course will only use a few minutes from your free plan, but Azure requires the billing information.

  3. Install Azure CLI on your machine.
  4. In your terminal, run:
    az login
  5. Copy the value of the id: field to a safe place. We'll call this AZURE_SUBSCRIPTION_ID. Here's an example of what it looks like:
    [
    {
      "cloudName": "AzureCloud",
      "id": "f****a09-****-4d1c-98**-f**********c", # <-- Copy this id field
      "isDefault": true,
      "name": "some-subscription-name",
      "state": "Enabled",
      "tenantId": "********-a**c-44**-**25-62*******61",
      "user": {
        "name": "mdavis******@*********.com",
        "type": "user"
        }
      }
    ]
  6. In your terminal, run the command below. Note: The \ character works as a line break on Unix based systems. If you are on a Windows based system the \ character will cause this command to fail. Place this command on a single line if you are using Windows.
    az ad sp create-for-rbac --name "GitHub-Actions" --role contributor \
                              --scopes /subscriptions/{subscription-id} \
                              --sdk-auth
                              
    # Replace {subscription-id} with the same id stored in AZURE_SUBSCRIPTION_ID.
  7. Copy the entire contents of the command's response, we'll call this AZURE_CREDENTIALS. Here's an example of what it looks like:
    {
      "clientId": "<GUID>",
      "clientSecret": "<GUID>",
      "subscriptionId": "<GUID>",
      "tenantId": "<GUID>",
      (...)
    } 
  8. Back on GitHub, click on this repository's Secrets in the Settings tab.
  9. Click New secret
  10. Name your new secret AZURE_SUBSCRIPTION_ID and paste the value from the id: field in the first command.
  11. Click Add secret.
  12. Click New secret again.
  13. Name the second secret AZURE_CREDENTIALS and paste the entire contents from the second terminal command you entered.
  14. Click Add secret
  15. Back in this pull request, edit the .github/workflows/deploy-staging.yml file to use some new actions, or use this quick link (We recommend opening the quick link in another tab)

If you'd like to copy the full workflow file, it should look like this:

name: Stage the app

on: 
  pull_request:
    types: [labeled]

env:
  DOCKER_IMAGE_NAME: petetian-azure-ttt
  IMAGE_REGISTRY_URL: docker.pkg.github.com
  #################################################
  ### USER PROVIDED VALUES ARE REQUIRED BELOW   ###
  #################################################
  #################################################
  ### REPLACE USERNAME WITH GH USERNAME         ###
  AZURE_WEBAPP_NAME: petetian-ttt-app
  #################################################

jobs:
  build:
    if: contains(github.event.pull_request.labels.*.name, 'stage')

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: npm install and build webpack
        run: |
          npm install
          npm run build
      - uses: actions/upload-artifact@main
        with:
          name: webpack artifacts
          path: public/

  Build-Docker-Image:
    runs-on: ubuntu-latest
    needs: build
    name: Build image and store in GitHub Packages
    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Download built artifact
        uses: actions/download-artifact@main
        with:
          name: webpack artifacts
          path: public

      - name: create image and store in Packages
        uses: mattdavis0351/actions/[email protected]
        with:
          repo-token: ${{secrets.GITHUB_TOKEN}}
          image-name: ${{env.DOCKER_IMAGE_NAME}}

  Deploy-to-Azure:
    runs-on: ubuntu-latest
    needs: Build-Docker-Image
    name: Deploy app container to Azure
    steps:
      - name: "Login via Azure CLI"
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - uses: azure/docker-login@v1
        with:
          login-server: ${{env.IMAGE_REGISTRY_URL}}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy web app container
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{env.AZURE_WEBAPP_NAME}}
          images: ${{env.IMAGE_REGISTRY_URL}}/${{ github.repository }}/${{env.DOCKER_IMAGE_NAME}}:${{ github.sha }}

      - name: Azure logout
        run: |
          az logout

I'll respond when you push a commit on this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants