diff --git a/config.yml b/config.yml index c5b1e36..2fa30aa 100644 --- a/config.yml +++ b/config.yml @@ -20,6 +20,12 @@ before: # production-deployment-workflow: with the workflow file stub for production deploy from merge # staging-test: with a small change to the app that can be seen in staging + # we create a staging label that will be used later to test + +- type: createLabel + name: stage + color: f87000 + # PART 1: STAGING WORKFLOW # Step 1: Configure a trigger based on labels @@ -39,7 +45,7 @@ steps: - title: Configure a trigger based on labels description: Configure the workflow trigger based on an a label being added event: pull_request - link: '{{ repoUrl }}/pulls/1' + link: '{{ repoUrl }}/pull/1' actions: # We validate that trigger is correct #- type: gate @@ -54,7 +60,7 @@ steps: - title: Choose the environment for AWS description: Choose the Ubuntu environment for our app event: pull_request - link: '{{ repoUrl }}/pulls/1' + link: '{{ repoUrl }}/pull/1' actions: # We validate @@ -69,24 +75,25 @@ steps: - title: Write the steps for the staging workflow description: Write the steps for the staging deployment workflow event: pull_request - link: '{{ repoUrl }}/pulls/1' + link: '{{ repoUrl }}/pull/1' actions: # We validate #- type: gate - # We approve - - type: createReview - event: APPROVE + # We remove branch protections + - type: removeBranchProtection + # Step 4: Merge the staging workflow # We tell the user to merge - body: 04_merge.md + - type: respond + with: 04_merge.md # event: merge - title: Merge the staging workflow description: Merge this staging workflow pull request event: pull_request.closed - link: '{{ repoUrl }}/pulls/1' + link: '{{ repoUrl }}/pull/1' actions: # we make sure it's merged @@ -98,6 +105,8 @@ steps: right: closed - left: '%payload.pull_request.merged%' + # we reprotect master for the next PR + - type: updateBranchProtection # PART 2: AWS CONFIGURATION @@ -118,10 +127,10 @@ steps: # event: responding with a comment -- title: Confirm AWS configuration +- title: Confirm AWS S3 configuration description: Create an AWS account by the following specifications, and confirm here event: issue_comment.created - link: '{{ repoUrl }}/pulls/2' + link: '{{ repoUrl }}/pull/2' actions: # Step 6: Enter environment variables @@ -132,10 +141,10 @@ steps: with: 06_env-variables.md # event: Respond with a comment -- title: Enter environment variables - description: Enter your AWS environment variables into this repository, and confirm here +- title: Create and store environment variables + description: Create your AWS IAM secrets and enter them in this repository event: issue_comment.created - link: '{{ repoUrl }}/pulls/2' + link: '{{ repoUrl }}/pull/2' actions: # Validate if possible @@ -147,12 +156,16 @@ steps: - type: respond with: 07_approve.md + # we formally request their approval + - type: requestReviewFromRegistrant + pullRequest: Configure AWS + # event: approval - title: Approve pull request description: Approve pull request adding the aws-config.yml and sam-template.yml event: pull_request_review - link: '{{ repoUrl }}/pulls/2' + link: '{{ repoUrl }}/pull/2' actions: # we make sure it's approved @@ -191,7 +204,7 @@ steps: - title: Test the staging action description: Test the new action to deploy labeled pull requests to staging event: pull_request.labeled - link: '{{ repoUrl }}/pulls/3' + link: '{{ repoUrl }}/pull/3' actions: # We need to prepare next PR for them where they write the prod deployment workflow @@ -216,7 +229,7 @@ steps: - title: Write the production deployment trigger description: Write the production deployment trigger in the new workflow event: pull_request - link: '{{ repoUrl }}/pulls/3' + link: '{{ repoUrl }}/pull/3' actions: # We validate @@ -233,7 +246,7 @@ steps: - title: Choose the environment for AWS description: Commit the proper environment for AWS to the workflow file event: pull_request - link: '{{ repoUrl }}/pulls/3' + link: '{{ repoUrl }}/pull/3' actions: # We validate @@ -250,7 +263,7 @@ steps: - title: Write the steps for the production workflow description: Write the steps for the production deployment to the workflow file event: pull_request - link: '{{ repoUrl }}/pulls/3' + link: '{{ repoUrl }}/pull/3' actions: # We validate @@ -261,18 +274,19 @@ steps: # Step 12: Merge this pull request and test the production deployment workflow -# We tell the user to merge, and that their merge will bring the action into `master`, and will also create a deployment into production - - type: createReview - body: 12_merge.md - event: APPROVE +# We remove branch protections + - type: removeBranchProtection +# We tell the user to merge, and that their merge will bring the action into `master`, and will also create a deployment into production + - type: respond + with: 12_merge.md # event: merge -- title: Merge this pull request +- title: Merge the production workflow description: Merge this pull request and test the production deployment workflow event: pull_request.closed - link: '{{ repoUrl }}/pulls/3' + link: '{{ repoUrl }}/pull/3' actions: # check that its merged diff --git a/course-details.md b/course-details.md index e69de29..cceb547 100644 --- a/course-details.md +++ b/course-details.md @@ -0,0 +1,9 @@ +This course is about continuous delivery, or CD, with GitHub Actions. We create two workflows to deploy our app to an AWS S3 bucket automatically. CD is an important part of modern software development, and it has a big meaning. CD is the practice of delivering software faster and with higher quality. To do this, it takes many different practices, behaviors, and technologies. + +In this course, we focus on workflows to deploy pull requests automatically to a staging environment, and to deploy all merged commits to production. In this course, you will: + +- Create two workflow files +- Configure AWS S3 for deployment +- Use secrets to store tokens +- Deploy to staging and production +- Practice using GitHub Actions \ No newline at end of file diff --git a/responses/01_label-trigger.md b/responses/01_label-trigger.md index f7510af..4148fe6 100644 --- a/responses/01_label-trigger.md +++ b/responses/01_label-trigger.md @@ -6,13 +6,38 @@ We will be working with Continuous Delivery. We will... - Use AWS configuration Before you start, you should... -- Introduction to GitHub -- Continuous Integration with GitHub Actions +- [Introduction to GitHub](https://lab.github.com/githubtraining/introduction-to-github) +- [Continuous Integration with GitHub Actions](https://lab.github.com/githubtraining/set-up-continuous-integration-with-github-actions) ### What is Continuous Delivery? -I'll tell ya! +According to [continuousdelivery.com](https://continuousdelivery.com/), + +> Continuous Delivery is the ability to get changes of all types—including new features, configuration changes, bug fixes and experiments—into production, or into the hands of users, safely and quickly in a sustainable way. + +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. ## Step 1: Configure a trigger based on labels +During the `on` step, we define what should cause this workflow to run. In this case, we want the workflow to run whenever a label is applied to the pull request. + ### :keyboard: Activity: Configure the workflow trigger based on an a label being added + +1. Edit this file +2. Change the name of the directory `CHANGETHIS` to `workflows`, so the title of this file with the path is `.github/workflows/staging-workflow.yml` +3. Edit the contents of this file to trigger on a label + +Your result should look like this: + +```yml +name: Staging deployment + +on: + pull_request: + types: [labeled] + +jobs: + build: + if: contains(github.event.pull_request.labels.*.name, 'stage') + +``` \ No newline at end of file diff --git a/responses/02_environment.md b/responses/02_environment.md index 63faca3..7379be0 100644 --- a/responses/02_environment.md +++ b/responses/02_environment.md @@ -1,7 +1,27 @@ # Choosing deployment environments -We will be working with AWS for the deployment environment. AWS will do the work of creating the environment, but first, we need to tell it what we need. That happens in the `environment` section of the workflow file. You have many options here, but for our purpose, we will be using a basic Ubuntu environment for our Node.js application. +We will be working with AWS for the deployment environment. AWS will do the work of creating the environment, but first, we need to tell it what we need. That happens in the `environment` section of the workflow file. + +### What are the options? + +You may want to choose a different environment based on your application. You can read more about [virtual environments for GitHub Actions](https://help.github.com/en/github/automating-your-workflow-with-github-actions/virtual-environments-for-github-actions) on GitHub Help. ## Step 2: Choose the environment for AWS -### :keyboard: Activity: Choose the Ubuntu environment for our app \ No newline at end of file +For our `Node.js` application, we will be using a basic Ubuntu environment. + +### :keyboard: Activity: Choose the Ubuntu environment for our app + +```yml +name: Staging deployment + +on: + pull_request: + types: [labeled] + +jobs: + build: + if: contains(github.event.pull_request.labels.*.name, 'stage') + + runs-on: ubuntu-latest +``` \ No newline at end of file diff --git a/responses/03_workflow-steps.md b/responses/03_workflow-steps.md index 3c67edd..c6e4c37 100644 --- a/responses/03_workflow-steps.md +++ b/responses/03_workflow-steps.md @@ -4,4 +4,54 @@ So far, the workflow knows what the trigger is and what environment to run in. B ## Step 3: Write the steps for the staging workflow -### :keyboard: Activity: Write the steps for the staging deployment workflow \ No newline at end of file +We won't be going into detail on the steps of this workflow, but it would be a good idea to check them out. You'll see that we're adding steps using existing actions for: + +- `actions/checkout` +- `Deploy to AWS` + +### :keyboard: Activity: Write the steps for the staging deployment workflow + +```yml +name: Staging deployment + +on: + pull_request: + types: [labeled] + +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@master + with: + name: webpack artifacts + path: public/ + + deploy: + name: Deploy Node.js app to AWS + needs: build + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Download built artifact + uses: actions/download-artifact@master + with: + name: webpack artifacts + path: public + + - name: Deploy to AWS + uses: docker://admiralawkbar/aws-nodejs:latest + env: + AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }} +``` \ No newline at end of file diff --git a/responses/04_merge.md b/responses/04_merge.md index 7238d1c..8a90d84 100644 --- a/responses/04_merge.md +++ b/responses/04_merge.md @@ -1,9 +1,12 @@ # Completed Workflow -Nice job, you've done it! +Nice job, you've done it! It won't be "working" yet, because our next step is to work on the configuration files that AWS will need. But, the logic for this workflow is complete. ## Step 4: Merge the staging workflow -### :keyboard: Activity: Merge this staging workflow pull request \ No newline at end of file +### :keyboard: Activity: Merge this staging workflow pull request + +1. Merge this pull request +2. Delete the `staging-workflow` branch` \ No newline at end of file diff --git a/responses/05_confirm-aws.md b/responses/05_confirm-aws.md index 0c371a4..ceab158 100644 --- a/responses/05_confirm-aws.md +++ b/responses/05_confirm-aws.md @@ -1,5 +1,19 @@ -# AWS Configuration +# AWS Configuration - S3 Buckets -## Step 5: Confirm AWS configuration +For deployment, we will be using AWS. -### :keyboard: Activity: Create an AWS account by the following specifications, and confirm here. +### S3 Buckets + +Amazon S3 Buckets are containers. They're also a very flexible type of data storage- they can be configured to work in many different types of ways. They're popular for their security, scalability, and dependability. Our S3 Bucket will be the container that our application is deployed in, both in staging and in production. + +## Step 5: Confirm AWS S3 configuration + +### :keyboard: Activity: Create an AWS account by the following specifications, and confirm here + +1. Create an account at [aws.amazon.com](https://aws.amazon.com/) + - _This requires credit card information. If you'd like to continue with the course without an AWS account, Learning Lab will still respond, but none of the deployments will work._ +2. [Create an S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html) + - If you aren't sure how to get there, you can search for `S3`. + - The region needs to be the same as what is specified in the `aws-config.yml` file in this pull request. :eyes: **For this exercise, choose us-west-2**. :eyes: If you'd like to choose another region, make sure to update the `aws-config.yml` file to match. + - For all other options, accept the defaults. +3. Confirm that you've created an S3 bucket by commenting anything in this pull request \ No newline at end of file diff --git a/responses/06_env-variables.md b/responses/06_env-variables.md index 30b15c0..9576097 100644 --- a/responses/06_env-variables.md +++ b/responses/06_env-variables.md @@ -1,7 +1,29 @@ # Environment Variables -## Step 6: Enter environment variables +### Access keys for IAM Users -### :keyboard: Activity: Enter your AWS environment variables in this repository +To automate the authentication, AWS recommends using a process called [IAM users](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html). By creating a specific key for a purpose or individual, specific scopes can be specified and access can be tracked. -Then confirm you've done that by commenting. \ No newline at end of file +When you create an access key, the key pair is active by default, and you can use the pair right away. You will be adding the following two secrets to this repository: + +- **AWS_ACCESS**: This serves as the user identifying token. "Access key ID" +- **AWS_SECRET**: This represents the secret key value pair that's like a password. It's under "Secret access key". + +## Step 6: Create and store environment variables + +### :keyboard: Activity: Create your AWS IAM secrets and enter them in this repository + +1. Add the tokens to this repository with the token name `AWS_SECRET_KEY` +2. Once you are done, confirm here by commenting anything in this pull request +3. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam/ +4. In the navigation pane, choose **Users** +5. Create a new user with **programmatic access** +6. When setting permissions, search for and select **AmazonS3FullAccess** +7. Use a tag that will identify this token pair, like **Deployment Learning Lab** +8. **Download .csv file** to save the access key ID and secret access key to a CSV file on your computer + - Store the file in a secure location + - ⚠️ _You will not have access to the secret access key again after this dialog box closes_ + - After you download the CSV file, choose **Close** +9. Save the _Access key ID_ as a secret, named `AWS_ACCESS_KEY` in the **Settings > Secrets** +10. Save the _Secret access key_ as a secret, named `AWS_SECRET_KEY` in the **Settings > Secrets** +11. Once you are done, confirm here by commenting anything in this pull request diff --git a/responses/07_approve.md b/responses/07_approve.md index 300484c..40b069d 100644 --- a/responses/07_approve.md +++ b/responses/07_approve.md @@ -1,7 +1,23 @@ # AWS Configuration files -This is what those files are: +To deploy successfully to our S3 bucket on AWS, we need a few special configuration files. + +### `aws-config.yml` + +The `aws-config.yml` file is needed with the `Deploy to AWS` Action that we're using. **How did we know that it's needed?** In the [documentation for the GitHub action](https://github.com/github/deploy-nodejs), there are specific instructions about including this file, and where it needs to sit within the repository. + +Whenever you're using a GitHub Action, it's important to read the documentation. There may be details like what secrets or other template files are required for the Action to work as expected. + +### `sam-template.yml` + +This file is a bit trickier. The template `aws-config.yml` file that was documented with the action has a placeholder for this template, but doesn't specify what we should do. + +In our case, we created the `sam-template.yml` for you. It contains information that's specific about the application source code in this repository. When we tell AWS to deploy, it wonders "Deploy _what_?". This file communicates which files should be deployed, and how, within our S3 bucket on AWS. ## Step 7: Approve the pull request -### :keyboard: Activity: Approve pull request adding aws-config.yml and sam-template.yml \ No newline at end of file +I've requested your approval on this pull request. Once you approve this, I will merge. + +### :keyboard: Activity: Approve pull request adding `aws-config.yml` and `sam-template.yml` + +1. Approve this pull request \ No newline at end of file diff --git a/responses/08_deployment.md b/responses/08_deployment.md index 6793ac5..da6cba7 100644 --- a/responses/08_deployment.md +++ b/responses/08_deployment.md @@ -1,3 +1,3 @@ The deployment may take a few moments but you've done the right thing. Once the deployment is successful, you can move on to the next steps in the [next pull request]({{ url }}). -If you'd like to come back and merge this once their other workflow is done, they can. \ No newline at end of file +If you'd like to come back and merge this once their other workflow is done, you can. :tada: \ No newline at end of file diff --git a/responses/08_test.md b/responses/08_test.md index 62102bc..d1a02f0 100644 --- a/responses/08_test.md +++ b/responses/08_test.md @@ -6,4 +6,7 @@ Now that the proper configuration and workflow files are present, let's test thi In this pull request, there's a small change to the game. Once you add the label, you should be able to see the deployment! -### :keyboard: Activity: Add the proper label to this pull request \ No newline at end of file +### :keyboard: Activity: Add the proper label to this pull request + +1. On the right hand side, click **Add label** +2. Select the label titled **stage** diff --git a/responses/09_merge-trigger.md b/responses/09_merge-trigger.md index f5f99ff..b8c75c2 100644 --- a/responses/09_merge-trigger.md +++ b/responses/09_merge-trigger.md @@ -4,4 +4,16 @@ For the deployment to production, the trigger will be a merge to master. ## Step 9: Write the production deployment trigger -### :keyboard: Activity: Write the production deployment trigger on merge to master \ No newline at end of file +### :keyboard: Activity: Write the production deployment trigger on merge to master + +1. First, change the `CHANGETHIS` directory to `workflows` +2. Make the file look like this + +```yml +name: Production deployment + +on: + push: + branches: + - master +``` \ No newline at end of file diff --git a/responses/10_environment.md b/responses/10_environment.md index 3956cfd..7c2fdcc 100644 --- a/responses/10_environment.md +++ b/responses/10_environment.md @@ -1,7 +1,24 @@ # Choosing an environment -Just like with the other workflow, we will need to specify an environment for AWS. +Just like with the other workflow, we will need to specify an environment for AWS. We will choose the same environment because we are working with the same `Node.js` app. + +**Continuous delivery** is a concept that contains many behaviors and other, more specific concepts. One of those concepts is **test in production**. That can mean different things to different projects and different companies, and isn't a strict rule that says you are or aren't "doing CD". + +In our case, we can match our production environment to be exactly like our staging environment. This minimizes opportunities for surprises once we deploy to production. ## Step 10: Choose the environment for AWS -### :keyboard: Choose an Ubuntu environment for the production deployment \ No newline at end of file +### :keyboard: Choose an Ubuntu environment for the production deployment + +```yml +name: Production deployment + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest +``` \ No newline at end of file diff --git a/responses/11_workflow-steps.md b/responses/11_workflow-steps.md index 9c27462..6a719bb 100644 --- a/responses/11_workflow-steps.md +++ b/responses/11_workflow-steps.md @@ -2,6 +2,83 @@ 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 specify what actions to be run in the Ubuntu environment when new labels are added. +With the staging deployment, we use `checkout` and `Deploy to AWS`. In this workflow, we use: + +- `actions/checkout@v1` +- `Deploy to AWS` + +We also have a new section past the `deploy` section, called **Docker Build, Tag, Push**, or Build-and-Push-Docker-Image. This part of the workflow uses the action from another course. That action builds the code, tags the commit, and pushes a package to the GitHub Package Registry. + +- `actions/checkout@v1` +- `actions/download-artifact@master` +- `mattdavis0351/actions/docker-gpr@v1` + +All of this happens automatically once a pull request is merged! + ## Step 11: Write the steps for the production workflow -### :keyboard: Activity: Write the steps for the production deployment workflow \ No newline at end of file +### :keyboard: Activity: Write the steps for the production deployment workflow + +```yml +name: Production deployment + +on: + push: + branches: + - master + +jobs: + build: + 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@master + with: + name: webpack artifacts + path: public/ + + deploy: + name: Deploy Node.js app to AWS + needs: build + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Download built artifact + uses: actions/download-artifact@master + with: + name: webpack artifacts + path: public + + - name: Deploy to AWS + uses: docker://admiralawkbar/aws-nodejs:latest + env: + AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }} + + Build-and-Push-Docker-Image: + runs-on: ubuntu-latest + needs: build + name: Docker Build, Tag, Push + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Download built artifact + uses: actions/download-artifact@master + with: + name: webpack artifacts + path: public + + - name: Build, Tag, Push + uses: mattdavis0351/actions/docker-gpr@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + image-name: tic-tac-toe +``` \ No newline at end of file diff --git a/responses/12_merge.md b/responses/12_merge.md index 0d8450f..b6f4224 100644 --- a/responses/12_merge.md +++ b/responses/12_merge.md @@ -1,7 +1,10 @@ # Completed Workflow -Nice job, you've done it! +Nice job, you've done it! -## Step 12: Merge the staging workflow +## Step 12: Merge the production workflow -### :keyboard: Activity: Merge this production workflow pull request \ No newline at end of file +### :keyboard: Activity: Merge this pull request and test the production deployment workflow + +1. Merge this pull request +2. Delete the branch \ No newline at end of file