diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd4f2b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4f4c47 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 The GitHub Training Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.docs.md b/README.docs.md new file mode 100644 index 0000000..43aecbe --- /dev/null +++ b/README.docs.md @@ -0,0 +1,47 @@ +** # Deprecated please do not follow links in this guide** +# Migrating to GitHub Actions Facilitator Guide + +Welcome to the Migrating to GitHub Actions offering repo. In this repo, you will find the content used by GitHub during our official actions training and consulting. + +If you have access to this repository, it is because your company has an agreement with GitHub to use these materials. Your use of these materials is described by that agreement. + +## Deploy the manual + +This guid is currently deployed to GitHub pages and can be found here + +If you would like to contribute to the guide follow the steps in the **Preview changes on your machine** section. + + + +## Make changes + +The official [docsify documentation](https://docsify.js.org/#/?id=docsify) is your best bet for getting up to speed with the tool. + +In general, you'll find all of the manual content in the [`docs/`](docs/) folder of this repository. All content is written in Markdown, and it's all stitched together in [`docs/_sidebar.md`](docs/_sidebar.md), which specifies the order and hierarchy of the content. + +#### Mermaid-js + +This manual makes use of [mermaid-js](https://mermaid-js.github.io/mermaid/#/) specifically for the use of `stateDiagram`. Should you need to update, or want to add, a new `stateDiagram` using this library will allow the custom CSS to be applied for consistency. + +Any diagrams can be written directly in markdown with the [mermaid syntax](https://mermaid-js.github.io/mermaid/#/stateDiagram) however it is important to note that docsify and mermaid struggle to work well together, so once a new `stateDiagram` is created it is best to save a screenshot of it and use it within the markdown vs the raw mermaid chart. + +Doing so will prevent mermaid from breaking as you go to a new page. + +## Preview changes on your machine + +You can install, and serve the contents of the `docs/` folder locally with minimal setup. The steps are thoroughly described in the [doscify quick start](https://docsify.js.org/#/quickstart) guide. + +**steps:** + +1. `npm i docsify-cli -g` +2. `docsify serve docs` + +View the locally running version of this guide at `http://localhost:3000` diff --git a/README.md b/README.md new file mode 100644 index 0000000..7efc80f --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# GitHub-Actions-Docker-training +Training exercise repository for GitHub Actions using a docker base. This repository should be cloned and used for training purposes. Once cloned, the user can follow the directions inside to help understand how to set up basic and complex **Github Actions**. + +## How to Use +- Clone this repository to your local **GitHub organization** or **user account** + - You can do so by [changing the repository's remote URL](https://docs.github.com/en/free-pro-team@latest/github/using-git/changing-a-remotes-url) with + ``` + git remote set-url origin https://github.com/USERNAME/REPOSITORY.git + ``` +- Locate the `Exercises` folder +- Follow [the directions](https://github.com/githubtraining/GitHub-Actions-Docker-training/blob/main/Exercises/README.md) for individual use cases at your leisure diff --git a/assets/case-study-pdfs/coletiv case study.pdf b/assets/case-study-pdfs/coletiv case study.pdf new file mode 100644 index 0000000..f640594 Binary files /dev/null and b/assets/case-study-pdfs/coletiv case study.pdf differ diff --git a/assets/facilitator-assets/manual.md b/assets/facilitator-assets/manual.md new file mode 100644 index 0000000..bf36c1c --- /dev/null +++ b/assets/facilitator-assets/manual.md @@ -0,0 +1,222 @@ +# Delivery guidance + +This document is designed to help facilitators understand the intent of the sections within this guide. Alongside intent, facilitators will find additional questions and discussion topics throughout this document that will aide them in the presentation of this offering. + +**This is meant to be an internal document**. + +#### Notes + +As per the facilitators discretion, based on your scoping call with the customer, take time at the end of each section to discuss implementing the preceding training into the project that was decided upon. + +This will allow the customer to immediately apply what they learned to an implementation plan for their project. + +--- + +## Getting Started + +### 00.0_getting-started.md + +#### Purpose + +This activity is just an opportunity for introductions and for the facilitator to start to gauge the current level of GitHub Actions familiarity. This activity is best served in a round robin approach with everyone in the room having a few seconds to introduce themselves. + +This is especially important when the people attending are **not** a part of the same team or organization! + +#### Notes + +Although this activity is slated for **~15 minutes** there are many cases where this could be a much shorter, or longer activity. These timings are loose and cab be flexible to meet the needs of the group attending the offering. + +#### Questions + +During delivery, some attendees may have prior CI/CD, automation or actions experience. In that event here are some follow up questions that can be asked to make the conversation more robust. + +- Do you find yourself using community driven actions or are you confined to private actions? +- What are some of the benefits you've gained from using actions opposed to another platform? +- Can you describe the process you used while adopting GitHub Actions? +- Have you written any custom actions? + - Were they Docker container or JavaScript actions? + - Did you publish them to the marketplace? + - Are they open-source? +- How does you currently share workflows/actions across teams? + +--- + +## Introduction to GitHub Actions + +### 01.0_actions-intro.md + +#### Notes + +This portion of the presentation introduces the first of many workflows. This workflow is incredibly simple and attempts to demonstrate the very basics of how a workflow executes. + +It is advisable to keep it very high-level at this point as there are many more workflow snippets that cover more complex use cases as you progress through the presentation. + +### 01.1_actions-about.md + +#### Purpose + +This portion introduces us to the first of many case studies surrounding GitHub Actions. Although it may seem a bit early to introduce a case study, the purpose of this examination is not to dive deep into actions. Rather, this case study exists at this point because Coletiv used workflows that were **not overly complex** to reach their desired end state. + +This was also Coletiv's first attempt at integrating GitHub Actions into their software development life cycle. + +#### Notes + +Although we will ideally keep things relatively high level at this point in the training, the two workflows presented in this case study do offer the facilitator the ability to go into more detail if the attendees of this offering have some experience with GitHub Actions. + +A nice thing to highlight here is the variety of techniques used for a given step in their workflows. For example, some steps use `run` commands, others use public actions from the community and the remaining use the actions that are maintained by GitHub. + +#### Questions + +If the discussion at the end of the case study does not yield the desired results, here are some ideas to help create a better experience: + +1. Consider adding discussion around these keys in the yaml file: + +- env +- if +- with + +2. Be advised that you may be asked about the differences between `with` and `env` while covering this case study, you can elaborate here or you can defer to a section that will cover those keywords later. + +3. You could potentially discuss how the branch filtering and step logic are working together, again that is covered a bit later. + +4. You can also point the attendees to the actual article to look through that as well, there are some pictures of the output and intermediate workflow files they worked with. + +### 01.2_actions-pricing.md + +#### Purpose + +This slide exists to show the pricing model. + +#### Notes + +We think it's best to not only talk about pricing here, but also to help define what counts as "usage". + +A major point to make here, is that under the **free** tier the pricing and usage limits apply to **private repos** and not their **public repos**. + +### 01.3_actions-starter-workflows.md + +#### Purpose + +Getting started with GitHub Actions is easy. There are templates to help you get going. + +#### Notes + +This is a really good opportunity to break from the presentation and go explore a few of these starter workflows in the actions tab of a repository. + +### 01.4_actions-hello.md + +#### Purpose + +This exercise will take the course to Learning Lab to get a little hands on experience with writing a really basic "hello world" for workflows. + +#### Notes + +As a facilitator, you should familiarize yourself with each of these courses so you can answer questions and troubleshoot the course if need be. + +We recommend guiding the attendees through these courses by doing it alongside of them and having them keep pace with you as you progress through the lab. + +**Changes to Learning Lab and the courses within it, especially those which utilize actions, happen frequently. Please go through the Learning Path with a fresh registration before every delivery to ensure there are no breaking changes.** + +If you do notice a breaking change contact the `services-programs` team by opening an issue in the [services repo](https://github.com/github/services) using the `Programs: Request Help` issue template. + +--- + +## Creating Workflows + +### 02.1_actions-ecosystem.md + +#### Purpose + +The overarching purpose of this section is to get the attendees very comfortable with writing workflow files. + +#### Notes + +This section contains as series of diagrams made with `Mermaid.js`. The digram in this file should read like this: + +- Events trigger workflows +- Workflows contain jobs +- Jobs are what are responsible for execution of actions +- During, and after, action execution status reports about the workflow run are generated. + +The arrows don't label well with `docsify` and `Mermaid.js` but are intended to be a cause and effect sort of relationship. + +### 02.2 through 02.5 + +#### Purpose + +I wanted to really dive into the keywords in the workflow syntax and spend some time explaining all of the options each bring to the table. + +You will find supporting workflow snippets that show how to implement these keywords and their options. + +#### Notes + +Again, these diagrams are designed to show at which phase in a workflow life cycle the current component exists. I have also expanded all of the properties for a given component to help highlight the options available to those writing workflow files. + +### 02.6_reporting.md + +#### Purpose + +Since we don't interact with logs directly, I felt it necessary to add screenshot on what these may look like. + +#### Notes + +A really good use of this section would be to leave the presentation and go explore the logs in some public repositories. + +Here are a few repos that utilize actions that you can explore the logs of: + +[Pandas Python Library](https://github.com/pandas-dev/pandas/actions) +[Go Cobra Module](https://github.com/spf13/cobra/actions) +[NumPy Python Library](https://github.com/numpy/numpy/actions) +[Commander.js](https://github.com/tj/commander.js/actions) +[Free Code Camp](https://github.com/freeCodeCamp/freeCodeCamp/actions) + +Consider tracing back the logs to identify the exact event that triggered the workflow. Be sure to look at both failed and successful workflows for a complete experience. + +--- + +## Continuous Deliver/Deployment + +### 04.5_cd-learning-path.md + +#### Purpose + +Guide attendees through the specified courses in the Learning Path. + +#### Notes + +This path contains courses to deploy to Azure and AWS. Both of which require initial setup, such as having Azure and AWS accounts. + +You should at a minimum demo at least one of these courses if the attendees do not have the ability to create accounts on their own. + +You could, if you and the attendees want to, cover both of these courses. Even though the application in these courses is the same, the deployment method varies. + +- AWS deploys a Node.js app in a serverless fashion +- Azure deploys a Docker container with the same Node.js app inside of it + +Both have extra workflow examples if you'd like more material to talk through. + +--- + +## Action Overview + +### 05.5_actions-runner-env.md + +#### Purpose + +It is important that developers/users are aware of the runner nuances. This sections hopes to introduce more information about a runner and establish best practices in using what is already provide by the runner rather than rolling your own solution. + +#### Notes + +This section is a perfect spot to explore the environment variables within each runner. + +Some variables that are worth talking about are: + +- `GITHUB_ACTOR` +- `GITHUB_REF` +- `GITHUB_EVENT_NAME` + +It is also worthwhile to talk about how these variables work alongside as well as differ from the `github context` as there is a fair amount of naming overlap. + +The way Docker behaves in a runner is also something that should be discussed here. One point of contention that shows up in a lot of issues is that GitHub Actions overwrites the `workdir` when it spawns the Docker container. **There does not seem to be a way to change this behavior** as such, every containers working directory will be `/github/workspace/` and that makes working with Docker a bit challenging. + +A ton of software comes packed into these runners as well, so much that it doesn't make sense to include it in the presentation. This would be the perfect area to open the help docs and explore some of the available pieces of software so that the attendees have an idea of what exists. diff --git a/dependencies/Gemfile b/dependencies/Gemfile new file mode 100644 index 0000000..57baf92 --- /dev/null +++ b/dependencies/Gemfile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } + +gem "rubocop", "~> 0.82.0" +gem "rubocop-github", "~> 0.16.0" +gem "rubocop-performance", "~>1.7.1" +gem "rubocop-rails", "~> 2.5" +gem "rubocop-rspec", "~> 1.41.0" \ No newline at end of file diff --git a/dependencies/Pipfile b/dependencies/Pipfile new file mode 100644 index 0000000..091a76e --- /dev/null +++ b/dependencies/Pipfile @@ -0,0 +1,20 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +Django = "*" +django-cors-middleware = "*" +django-extensions = "*" +djangorestframework = "*" +PyJWT = "*" +six = "*" + +[requires] +python_version = "3.5" + +[pipenv] +allow_prereleases = true \ No newline at end of file diff --git a/dependencies/package.json b/dependencies/package.json new file mode 100644 index 0000000..cb9b902 --- /dev/null +++ b/dependencies/package.json @@ -0,0 +1,8 @@ +{ + "name": "demo-action", + "dependencies": { + "jsonlint": "^1.6.3", + "markdownlint-cli": "^0.26.0", + "prettyjson": "^1.2.1" + } +} diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/00.0_getting-started.md b/docs/00.0_getting-started.md new file mode 100644 index 0000000..3860ae0 --- /dev/null +++ b/docs/00.0_getting-started.md @@ -0,0 +1,23 @@ +## What can I expect? {docsify-ignore-all} + +> - Introductions +> - Discuss goals of the training +> - Detailed course on the GitHub Actions platform +> - Hands-on facilitator guided learning +> - Help with migrating a project to GitHub Actions +> - Discuss logistics (timing of course, recording, etc.) + +πŸ‘ˆ **Our focus will be on the topics you see listed on the left in the navigation bar** + +GitHub Actions makes it easy to automate all your software workflows. GitHub Actions enables you to: + +- Build, test, and deploy your code with world class CI/CD right from GitHub. +- Make code reviews, branch management, and issue triaging work the way you want through community and custom shareable components. + +### Exercises +Throughout this course we will be doing exercises that will build your knowledge of GitHub Actions. + +#### Prequisites +- Text Editor +- Docker +- A GitHub Account diff --git a/docs/01.0_actions-intro.md b/docs/01.0_actions-intro.md new file mode 100644 index 0000000..a5201cc --- /dev/null +++ b/docs/01.0_actions-intro.md @@ -0,0 +1,38 @@ +## Introduction to GitHub Actions {docsify-ignore-all} + +![actions-workflow-image](https://user-images.githubusercontent.com/6351798/82076100-8b096480-969a-11ea-95bc-ad25920867d9.png) + +### Actions + +Actions are sharable individual tasks that perform units of work. These units of work can do a multitude of things ranging from thanking new contributors to deploying your application to a cloud provider. + +Actions can be defined in multiple places: + +- Directly in your repository +- In an open sourced public repository +- GitHub Marketplace + +### Workflows + +You can have one action in a workflow or combine multiple actions for a more complex workflow. These custom workflows become the automated processes used in your repository. + +When a workflow is triggered by a defined GitHub event, the action then executes and you're provided with real-time logging right inside your GitHub repository! + +Workflows must be defined inside the `.github/workflows` directory of a repository. + +### Example: + +```yaml +# This ENTIRE file is a workflow +jobs: + build: + runs-on: ubuntu-latest + steps: + # This is an action, defined in an open source repository + - name: Checkout repository + uses: actions/checkout@v2 + + # This is also an action, defined directly inside this repository + - name: Hello World action + uses: ./.github/actions/hello-world-action +``` diff --git a/docs/01.1_actions-about.md b/docs/01.1_actions-about.md new file mode 100644 index 0000000..061c57c --- /dev/null +++ b/docs/01.1_actions-about.md @@ -0,0 +1,23 @@ +## About GitHub Actions {docsify-ignore-all} + +![actions-overview](https://user-images.githubusercontent.com/6351798/82087024-936a9b00-96ac-11ea-9379-099063e9b528.png) + +GitHub Actions enable custom software development life cycles to be created alongside the existing source code in your GitHub repository. + +GitHub Actions allow you to: + +- Run a custom workflow triggered by ANY GitHub event +- Run simultaneous tests across multiple operating systems and runtimes +- Use GitHub-hosted runners for every major operating system or use self-hosted runners on premises or in the cloud +- Run workflows directly in a virtual machine +- Run workflows inside of containers +- Build applications in your language of choice with versatile language support +- View real time workflow logs and easily share CI/CD failures +- Architect container orchestration using docker-compose +- Automate workflows quickly using starter workflows +- Share and consume actions in the [GitHub Marketplace](https://github.com/marketplace?type=actions) +- Get email notifications about workflow runs + +### Exercise 1 - Creating the Dockerfile +[exercise-1](Exercises/01-Create-Dockerfile.md ':include') + diff --git a/docs/01.2_actions-pricing.md b/docs/01.2_actions-pricing.md new file mode 100644 index 0000000..f15bbcf --- /dev/null +++ b/docs/01.2_actions-pricing.md @@ -0,0 +1,77 @@ +## Pricing {docsify-ignore-all} + +

+GitHub Actions is available for the following; GitHub Free, GitHub Pro, GitHub Team, GitHub Enterprise Cloud, and GitHub One. GitHub Actions is not available for private repositories owned by accounts using legacy per-repository plans. +

+ +| Product | Storage | Minutes (per month) | +| ----------------------- | ------- | ------------------- | +| GitHub Free | 500 MB | 2,000 | +| GitHub Pro | 1 GB | 3,000 | +| GitHub Team | 2 GB | 10,000 | +| GitHub Enterprise Cloud | 50 GB | 50,000 | + +## Usage Limits

\*subject to change + + + +#### **Job execution** + +# 6 Hours + +After 6 hours the job is terminated and is seen as a failed job. This limit does not apply to self-hosted runners. + +#### **Workflow run** + +# 72 Hours + +Reaching this limit will cancel the workflow. This limit also applies to self-hosted runners. + +#### **Job queue** + +# 24 Hours + +If a self-hosted runner does not start executing the job within this limit, the job is terminated and fails to complete. + +**This limit does not apply to GitHub-hosted runners.** + +#### **API requests** + +# 1000 per hour + +You can execute up to 1000 API requests in an hour across all actions within a repository. If exceeded, additional API calls will fail, which might cause jobs to fail. This limit also applies to self-hosted runners. + +#### **Job matrix** + +# 256 per run + +A job matrix can generate a maximum of 256 jobs per workflow run. + +**This limit also applies to self-hosted runners.** + +#### **Concurrent jobs** + +# Based on Plan + +The number of concurrent jobs you can run in your account depends on your GitHub plan. There are no concurrency limits for self-hosted runners. + +**See table below** + + + +| GitHub plan | Total concurrent jobs | Maximum concurrent macOS jobs | +| ----------- | --------------------- | ----------------------------- | +| Free | 20 | 5 | +| Pro | 40 | 5 | +| Team | 60 | 5 | +| Enterprise | 180 | 50 | + + +#### Pricing +| Operating System | Price Per Minute | +| ----------- | --------------------- | +| Linux | $0.008 | +| macOS | $0.08 | +| Windows | $0.016 | + +

Usage limits and pricing are subject to change, please visit the About billing for GitHub Actions page of the help documentation

diff --git a/docs/01.3_actions-starter-workflows.md b/docs/01.3_actions-starter-workflows.md new file mode 100644 index 0000000..95da5bc --- /dev/null +++ b/docs/01.3_actions-starter-workflows.md @@ -0,0 +1,9 @@ +## Starter Workflows {docsify-ignore-all} + +If all of that sounds intimidating have no fear, GitHub provides you with many **starter workflows** to help you get moving with GitHub Actions. + +_These, and many more, can be found by exploring the **Actions** tab within a repository._ + +![Starter Workflows](https://user-images.githubusercontent.com/38021615/75951540-18d9ff80-5e61-11ea-988a-63e17cb9b9c1.png) + +GitHub also allows you to create [**your own starter workflows for your organization**](https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/sharing-workflows-with-your-organization). \ No newline at end of file diff --git a/docs/01.4_actions-hello.md b/docs/01.4_actions-hello.md new file mode 100644 index 0000000..1ea61b8 --- /dev/null +++ b/docs/01.4_actions-hello.md @@ -0,0 +1,24 @@ +## Hands-on Activity πŸŽ‰ {docsify-ignore-all} + +![actions-learning-lab](https://user-images.githubusercontent.com/6351798/82087383-37544680-96ad-11ea-916a-2dba94bf52e3.png) + +We have put together an actions learning experience like no other. Through a series of guided courses, you will gain the necessary knowledge to begin implementing GitHub Actions into your repositories. + +**You'll complete tasks teaching you how to:** + +- Configure workflows within your repositories +- Implement continuous integration using GitHub Actions +- Implement continuous delivery using GitHub Actions +- Write custom JavaScript actions +- Write custom Docker container actions +- Publish applications to cloud providers +- Share actions across workflows and repositories +- Publish actions to the GitHub marketplace + +**To supplement these learning tasks you will be provided with facilitator led case studies that showcase:** + +- How GitHub uses GitHub Actions +- How other organizations have used GitHub Actions +- Cheat sheet reference materials + +Head over to the [**DevOps with GitHub Actions Learning Path**](https://lab.github.com/githubtraining/paths/devops-with-github-actions) diff --git a/docs/01.5_exercise-2.md b/docs/01.5_exercise-2.md new file mode 100644 index 0000000..6840845 --- /dev/null +++ b/docs/01.5_exercise-2.md @@ -0,0 +1,15 @@ +## Your First Action {docsify-ignore-all} +# Exercise 2 - A Basic CI Action + +[exercise-2](Exercises/02-Create-CI-Action.md ':include') + + +# Exercise 2 A - Protected Branches +[exercise2-a](Exercises/02.A-Create-QA-Branch.md ':include') + +# Exercise 2 B - Actions Context +[exercise2-b](Exercises/02.B-Create-Context-Job.md ':include') + +# Exercise 2 C - Manual Jobs +[exercise2-c](Exercises/02.C-Create-Manual-Job.md ':include') + diff --git a/docs/01.6_workflow-intro.md b/docs/01.6_workflow-intro.md new file mode 100644 index 0000000..721c761 --- /dev/null +++ b/docs/01.6_workflow-intro.md @@ -0,0 +1,5 @@ +## Congratulations πŸŽ‰ {docsify-ignore-all} + +![Mona the Octocat celebrating](https://user-images.githubusercontent.com/38021615/78980948-bca77280-7ad3-11ea-8510-485acaa02a7e.png) + +Now that you are acquainted with GitHub Actions, let's break down the ecosystem so we can better understand how these components really fit together. diff --git a/docs/02.10_secrets.md b/docs/02.10_secrets.md new file mode 100644 index 0000000..802fbda --- /dev/null +++ b/docs/02.10_secrets.md @@ -0,0 +1,22 @@ +## Secrets with Actions {docsify-ignore-all} + +Often it is necessary to use secrets within your workflows. Whether it is to authenticate to the API to notify users or connect to a cloud environment to deploy code. [GitHub Secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) is the way you connect your secrets with your workflows. + +Secrets can currently live at many levels: +- Organization +- Repository +- Environment + + +### Limits +[Per the GitHub documentation](https://docs.github.com/en/actions/reference/encrypted-secrets#limits-for-secrets) the limits for secrets are: +- 1000 Organization secrets +- 100 Repository secrets +- 100 Environment secrets +- 64KB in size + - [`gpg`](https://www.gnupg.org/gph/de/manual/r1023.html) can be used to encrypt files and store them in the repo if you need more space + +### Hiding Secrets +Secrets are encrypted with a [libsodium sealed box](https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes) and are not readable once you have stored them in your repository. +When secrets would get printed to the workflow logs, GitHub attempts to hide them on a best effort basis. This helps prevent accidental leaks of your secrets, but diligent users can easily find ways to get your secrets leaked, so ensure that only trusted users have write access to your workflows when using secrets + diff --git a/docs/02.11_continuous-integration.md b/docs/02.11_continuous-integration.md new file mode 100644 index 0000000..8ec4ab5 --- /dev/null +++ b/docs/02.11_continuous-integration.md @@ -0,0 +1,5 @@ +## Congratulations πŸŽ‰ {docsify-ignore-all} + +![Mona the Octocat celebrating](https://user-images.githubusercontent.com/38021615/78980948-bca77280-7ad3-11ea-8510-485acaa02a7e.png) + +Now that you are nice an acquainted with GitHub Actions and how to configure workflows, let's move into using this feature for Continuous Integration (CI). diff --git a/docs/02.1_actions-ecosystem.md b/docs/02.1_actions-ecosystem.md new file mode 100644 index 0000000..04869e8 --- /dev/null +++ b/docs/02.1_actions-ecosystem.md @@ -0,0 +1,18 @@ +## So how does this all work? πŸ€”{docsify-ignore-all} + +From 30,000 feet GitHub Actions is made up of the following components, with each component having its own complexities: + +

+ workflow metadata +

+ +| Component | Description | +| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Action | Individual tasks that you combine as **steps** to create a **job**. **Actions** are the smallest portable building block of a workflow. To use an **action** in a workflow, you must include it as a step. | +| Artifact | Artifacts are the files created when you build and test your code. Artifacts might include binary or package files, test results, screenshots, or log files. Artifacts can be used by the other jobs in the workflow or deployed directly by the workflow. | +| Event | A specific activity that triggers a workflow run. | +| Job | A defined task made up of steps. Each job is run in a fresh instance of the virtual environment. Jobs can run at the same time in parallel or be dependent on the status of a previous job and run sequentially. | +| Runner | Any machine with the GitHub Actions runner application installed. You can use a runner hosted by GitHub or host your own runner. A runner waits for available jobs. Runners run one job at a time reporting the progress, logs, and final result back to GitHub. | +| Step | A step is a set of tasks performed by a job. Steps can run commands or actions. | +| Virtual Environment | The virtual environment of a GitHub-hosted runner includes the virtual machine's hardware configuration, operating system, and installed software. | +| Workflow | A configurable automated process that you can set up in your repository. Workflows are made up of one or more jobs and can be scheduled or activated by an event. | diff --git a/docs/02.2_events.md b/docs/02.2_events.md new file mode 100644 index 0000000..5207dea --- /dev/null +++ b/docs/02.2_events.md @@ -0,0 +1,49 @@ +## Events {docsify-ignore-all} + + +

Events trigger workflows

+
+ +

+ events trigger workflows +

+ +### Webhook event types and payloads + +GitHub repository webhooks use event names to identify which event triggered any given webhook. These events can be used to define when a workflow is executed within a repository as well. + +### Finding events + +The best place to look for events that can be used to trigger workflows is at the [**events that trigger workflows**](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) documentation. + +Finding the proper event name can be a bit tricky so we will look at a couple examples below: + +| Event Type | Event Name | +| ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| [PushEvent](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#push) | `push` | +| [PullRequestEvent](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#pull_request) | `pull_request` | +| [IssuesEvent](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#issues) | `issues` | +| [DeploymentStatusEvent](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#deployment_status) | `deployment_status` | +| [WatchEvent](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#watch) | `watch` | + +### Event payloads + +The response payload of an event webhook can be used to apply more advanced filtering for a workflow's trigger. An easy example to look at is the [**ProjectEvent**](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads#project). + +

We will explore this further through later hands-on exercises.

+ +| Webhook Name | Activity Types | +| ------------ | -------------------------------------------------------------------------------------------------------- | +| `project` | | + +By specifying an event along with an activity type we can build more precise triggers that execute the workflows in a repository: + +```yaml +on: + project: + type: [created, reopened] +``` + +--- + +πŸ“–Learn more about [**events that trigger workflows**](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) and how to use them. diff --git a/docs/02.3_workflows.md b/docs/02.3_workflows.md new file mode 100644 index 0000000..9371d43 --- /dev/null +++ b/docs/02.3_workflows.md @@ -0,0 +1,54 @@ +## Worfklows {docsify-ignore-all} + + +

Workflows define wow to carry out tasks

+
+ +

+ workflow metadata +

+ +### Automating your software development lifecycle + +Workflows are the heart of your development process. They are custom automated processes that get setup right alongside the code in your repositories. Workflows can be used for many forms of automation. Tasks within a workflow range from building code and automated testing or other workflow automation processes like thanking new project contributors and reminding developers to review a pull request. + +### Connecting jobs to developers + +Thinking of a workflow as an interface between developers and task automation is a good place to start. It's here in the workflow that units of work, and how that work will be completed, get defined. This file also provides a location for developers to pass parameters and other necessary information to the individual actions that are being used to perform the work. + +Workflows are also used to define which events will trigger them and what environment variables will exist throughout the workflow. Lastly, workflows hold the definition of the jobs you wish to run when the workflow is triggered. + +### Constraints + +Workflow files aren't without their limitations. Keeping this list in mind will help your adoption of using workflows be a bit smoother. + +- People with write or admin permissions to a repository can create, edit, or view workflows. +- You must store workflows in the `.github/workflows` directory in the root of your repository. +- You can configure a workflow to start when a GitHub event occurs, on a schedule, or from an external event. +- You need to configure workflows using YAML syntax. +- More than one workflow can exist within a repository. + +### Example workflow File + +```yaml +name: Greet Everyone +# This workflow is triggered on pushes to the repository. +on: [push] + +jobs: + greet-users: + # Job name is Greeting + name: Greeting + # This job runs on Linux + runs-on: ubuntu-latest + steps: + # This step uses GitHub's hello-world-javascript-action: https://github.com/actions/hello-world-javascript-action + - name: Hello world + uses: actions/hello-world-javascript-action@v1 + with: + who-to-greet: "Mona the Octocat" + id: hello + # This step prints an output (time) from the previous step's action. + - name: Echo the greeting's time + run: echo 'The time was ${{ steps.hello.outputs.time }}.' +``` diff --git a/docs/02.4_jobs.md b/docs/02.4_jobs.md new file mode 100644 index 0000000..4f3d4e7 --- /dev/null +++ b/docs/02.4_jobs.md @@ -0,0 +1,41 @@ +## Jobs {docsify-ignore-all} + + +

Jobs define the environment and execution order for steps

+
+ +

+ keywords availble at the jobs level +

+ +### Executable tasks + +Until this point, the components we've talked about have been relatively supplementary to the actual unit of work we hope to achieve with a given workflow. It's not until we reach the point of defining jobs that we end up with tangible results. + +Jobs, defined in the workflow, have two main purposes: + +- Define the environment in which the subsequent steps will run +- Define one or more executable steps. + +### All about runners + +A major factor at the jobs level is defining the [**runner**](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#choosing-a-runner) that the job will execute on. To decide the proper runner for your use case, you first need to decide where that runner will be hosted. You have two hosting option for runners: + +- [**GitHub Hosted**](https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#about-github-hosted-runners) +- [**Self Hosted**](https://help.github.com/en/actions/hosting-your-own-runners) + +

For the purposes of this workshop we will be focusing on GitHub Hosted Runners. + +πŸ“–For more on insight on the administration of self-hosted runners, see the section [**Opting for Self-hosted Runners**](05.5b_self-hosted-runners.md).

+ +| GiHub Hosted | Self Hosted | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | + +Defining a runner is quite easy, and can be done so by specifying the desired runner within the jobs section of the workflow. + +```yaml +runs-on: ubuntu-latest +``` + +πŸ“–See a [**full list**](https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources) of runners and their environments diff --git a/docs/02.5_steps.md b/docs/02.5_steps.md new file mode 100644 index 0000000..b2c0e31 --- /dev/null +++ b/docs/02.5_steps.md @@ -0,0 +1,63 @@ +## Steps {docsify-ignore-all} + + +

A job contains a sequence of tasks called steps, our actual units of work in a workflow

+
+ +

+ keywords for a step +

+ +### Where the magic happens + +Steps are used to carry out the desired logic of the workflows within a repository. There are two step "types": + +- Actions (not to be confused with GitHub Actions) +- Commands (commands run from a the runners terminal such as `ping`) + +Both of these "types" may be mixed and matched within a single job. + +```yaml + +jobs: + my-job: + steps: + # My first step uses an action + - name: My first step + uses: monacorp/action-name@master + with: + some_input: some input value + + # My backup step uses a command + - name: My backup step + if: failure() + run: echo "Oops, something went wrong" +``` + +### Where do I find actions? + +Actions that can be consumed by your workflows can be found in a few different places. The first, and most prevalent place to find actions, is on the [GitHub Marketplace πŸ›’](https://github.com/marketplace?type=actions). Here you will find a plethora of actions developed by the open source community as well as first party actions developed by vendors. + +

+ workflow metadata +

+ +The second place to obtain actions is from **public** repositories across GitHub. You will find countless actions located in public repositories where the owners/maintainers of the action chose to not publish it to the marketplace. [This repository](https://github.com/mattdavis0351/actions) shows an example of public actions that aren't listed to the marketplace, but can be consumed publicly by anyone! + +Lastly, you may find yourself needing a some customization and privacy, and for that you will find actions in their third location... directly written in a private repository. These actions are **strictly scoped** to the repository they reside in and are **unable to be shared or published** + +### I found an action... now what? + +Once you decide on an action to use, you can reference it one of three ways: + +```yaml +- uses: actions/setup-node@74bc508 # Reference a specific commit +- uses: actions/setup-node@v1.0 # Reference the major version of a release +- uses: actions/setup-node@master # Reference a branch +``` + +--- + +

+Each step runs in its own process in the runner environment and has access to the workspace and filesystem. Because steps run in their own process, changes to environment variables are not preserved between steps. +

diff --git a/docs/02.6_reporting.md b/docs/02.6_reporting.md new file mode 100644 index 0000000..673ec90 --- /dev/null +++ b/docs/02.6_reporting.md @@ -0,0 +1,40 @@ +## Reporting {docsify-ignore-all} + +The last component of the workflow is to report status back to the repository. GitHub Actions does this in real time and these statuses can be found by going to the **Actions** tab within the desired repository. + +

+ actions tab location in repo +

+ +### View Repository Workflows + +From within the actions tab you will be greeted with a super quick overview of the workflows that are currently running in your repository. + +

+ enabled workflows in a repo +

+ +You will also see a quick status showing successes and failures of most recent runs of a given workflow. Timestamps, branch refs, actors and events that triggered the workflow are also summarized quickly in this view. + +

+ view of recent runs and their exit status +

+ +By clicking on a recent run you will be greeted with even more information about the workflow run. You can continue to drill down through this information until you eventually reach the step-by-step logs that stream in realtime as the workflow executes. + +

+ streaming logs of a step +

+ +
+ +#### Debugging +Sometimes it can be useful to see extra debug output from your workflows. To do this you can set the debug secret in the repository. +1. Open Repository Settings +1. Open Secrets +1. Add a new secret with the name `ACTIONS_RUNNER_DEBUG` and the value `true` +1. Notice that new workflows now have extra debug output + +--- + +

These logs are also available for download should you need to save them for any reason.

diff --git a/docs/02.7_exercise_3.md b/docs/02.7_exercise_3.md new file mode 100644 index 0000000..da14fac --- /dev/null +++ b/docs/02.7_exercise_3.md @@ -0,0 +1,7 @@ +## Updating Depenencies {docsify-ignore-all} +# Exercise 3 - Dependabot +[exercise-3](Exercises/03-Create-Dependabot-Config.md ':include') + +# Exercise 3 A - Dependency Locking +[exercise-3](Exercises/03.A-Lock-Dependencies.md ':include') + diff --git a/docs/02.8_actions-hackathon-case-study.md b/docs/02.8_actions-hackathon-case-study.md new file mode 100644 index 0000000..c4ea2e0 --- /dev/null +++ b/docs/02.8_actions-hackathon-case-study.md @@ -0,0 +1,175 @@ +## GitHub Actions Hackathon {docsify-ignore-all} + +

+GitHub Hackathon +

+ +### Hackathon case study + +In March of 2020, in an effort to boost the number of actions on the community marketplace, GitHub hosted a month long actions Hackathon. This virtual Hackathon lasted only four weeks but the community generated over 1000 submissions during that month. + +Some of the highlighted rules of the Hackthon were: + +- No teams! All Actions for the GitHub Actions Hackathon will need to be submitted by an individual. +- There is no limit to the number of submissions any individual could contribute. +- There is no specific topic or theme. You are welcome to create any type of Action that you’d like! Be creative and think outside the box. +- GitHub employees, contractors, and immediate family members cannot compete. + +**Problem** + +The team tasked with running this Hackathon went into the project with a lot of unknowns that needed solutions for a smooth Hackathon experience. + +- Unsure of how many developers would participate. +- As a global event time zones made it difficult to quickly provide feedback for submissions. +- Protecting the employees from angry developers who submissions had been turned away. +- What techniques would bad actors use to slip bad submissions through the cracks. + +This truncated list of problems would need to be addressed for every submissions that came through the Hackthon, which would equate to quite a few hours if done manually. Because of this, the team needed a way to be notified as submissions came in as well as process those submissions in a repeatable and reliable manner. + +Unfortunately, as the Hackathon went on, more unknowns crept up. Let's take a look at how the Hackathon team solved these workflow automation problems, to include the unknowns, using GitHub Actions. + +**Solution** + +Handling a submission: + +Because the Hackthon was a static site, the team needed to use a `repository_dispatch` event to kickoff their `handle-submission.yml` workflow. + +```yaml +name: "Handle Submission" +on: + repository_dispatch: + types: handle-submission + +jobs: + create-pr: + name: Create PR + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Process input + run: | + node utils/actions/process-input.js + - name: Run prettier + run: | + npx prettier data/**/*.json --write + - name: Create Pull Request + uses: peter-evans/create-pull-request@v2 + with: + token: ${{ secrets.GITHUB_TOKEN_PERSONAL }} + branch: create-pull-request/submission/${{ github.event.client_payload.repo }} + title: ${{ github.event.client_payload.id }} - ${{ github.event.client_payload.repo }} + body: | + Submitter: ${{ github.event.client_payload.user }} + Repository: ${{ github.event.client_payload.repo }} + Link: https://github.com/${{ github.event.client_payload.repo }} + > ${{ github.event.client_payload.description }} + labels: ${{ github.event.client_payload.id }}, submission +``` + +Since this was a submission based event, the ability to handle each submission in an automated manner saved the Hackathon team from needing to spend their time processing every submission and turning it into JSON. Once the JSON was properly created the final step of this workflow was to open a new pull request for that submission, which would trigger another workflow which was designed to run a series of validation checks. + +--- + +Validating a submission: + +Things that needed to be validated on a per submission basis included... + +- Verify the submitter of the action +- Ensure the submitted action was in a public repository +- Ensure the submission was accompanied by a license +- Validate that the action was actually an action. +- Check the commit history to ensure the action was developed according to the rules of the Hackathon + +Take a look at the workflow snippet below as it uses GitHub Actions in a somewhat unique way. What you should notice is that the Hackathon team created workflows which used a series of `run` commands to execute multiple JavaScript files rather than building a complex series of contained acitons. + +```yaml +jobs: + validate-submitter: + name: Validate submitter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Get PR info + run: | + node utils/actions/dist/get-pr-info + - name: Validate submitter + run: | + node utils/actions/dist/validate-submitter +``` + +The accompanying `utils/actions/dist/validate-submitter` file can be seen below + +```javascript +const { setFailed } = require("./comment"); +const github = require("@actions/github"); +const octokit = new github.GitHub(process.env.GITHUB_TOKEN); + +if (process.env.PR_SUBMITTER !== process.env.PR_REPO_OWNER) { + setFailed("Submitter does not own the repository"); +} + +octokit.repos + .getContents({ + owner: "github-hackathon", + repo: "hackathon", + path: "banned.txt", + }) + .then((res) => { + const bannedList = Buffer.from(res.data.content, "base64") + .toString() + .toLowerCase(); + if (bannedList.includes(process.env.PR_SUBMITTER.toLowerCase())) { + return setFailed("User has been marked as ineligible."); + } + }) + .catch((e) => setFailed(e)); +``` + +--- + +Protecting employees: + +By automating the processing and validation of a submission the team was able to find the necessary bandwidth to manually review each submission at this point. The manual process of reviewing the open pull requests was by design to allow the team to prevent bad actors as well as perform a quick "quality" check to decide if the action was a "bare-minimum" attempt or if it should be featured. + +Once a decision was made, the reviewer would apply a label to the pull request and GitHub Actions took over from there yet again. Any comments or feedback on the action were provided by the GitHub Actions bot, a special actor that exists within the feature, thus removing any one employee's name and profile from comments that could be received in a negative way. + +To accomplish this a unique public action name GitHub Script was consumed. We will cover more on GitHub Script later in a hands-on lab. + +For now, here is a quick look at what one of their many GitHub Script steps looked like. + +```yaml +- uses: actions/github-script@0.8.0 + name: Fork + if: github.event.label.name == 'fork' + with: + script: | + await github.issues.createComment({ + owner: "github-hackathon", + repo: "hackathon", + issue_number: context.payload.number, + body: "Submission is a fork and does not represent the submitter as the author." + }); + + await github.pulls.update({ + owner: "github-hackathon", + repo: "hackathon", + pull_number: context.payload.number, + state: "closed" + }); +``` + +**Outcome** + +The unintended outcome of what the Hackathon team did was create a way to validate that actions were written within a set of rules and adhered to an internal standard. This same practice can find itself useful to an organization by allowing teams to write their own actions, which are then put through an automated vetting process. + +Although for the Hackathon the teams main purpose was making sure rules were followed, your organization may consider adopting this practice and expanding it to ensure that actions meet security compliance, have necessary components to develop an audit trail, or simply conform to specific coding standards and use-cases. + + diff --git a/docs/02.9_caching.md b/docs/02.9_caching.md new file mode 100644 index 0000000..2a3b683 --- /dev/null +++ b/docs/02.9_caching.md @@ -0,0 +1,22 @@ +## Caching with Actions {docsify-ignore-all} + +Sometimes our workflows require us to pull down a large number of dependencies. As the time to download these dependencies goes up we can think about [caching them close to the Actions Runners](https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows) to speed up your run time. + +Take a look at [`actions/cache`](https://github.com/actions/cache) for samples +Sample Maven Workflow: + +``` +- name: Cache local Maven repository + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- +``` + +Things to keep in mind about caching on GitHub.com +- 5GB Max cache size per repository +- 7 Day data retention +- Scoped to key and branch +- Avoid caching sensitive data diff --git a/docs/03.1_ci-overview.md b/docs/03.1_ci-overview.md new file mode 100644 index 0000000..124d2a2 --- /dev/null +++ b/docs/03.1_ci-overview.md @@ -0,0 +1,24 @@ +## CI From 30,000ft ✈️ {docsify-ignore-all} + +

+ keywords availble at the jobs level +

+ +### What is CI? + +Integration of many changes from different developers into a trunk branch, not necessarily `master`, as early as possible. Ideally these integrations happen many times per day. The aim is to ensure the code an individual developer is working on doesn't divert too much from the rest of the team. + +This practice is usually accompanied by a series of automated tests. Although automated testing is not strictly a part of CI, a well oiled CI pipeline will utilize them as much as possible. + +### Advantages of Using CI + +> Software only becomes valuable when you ship it to customers. Before then it’s just a costly accumulation of hard work and assumptions. +> **\- Darragh Curran, VP of Engineering, Intercom** + +| Advantage | Explanation | +| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Reduced Risk | Frequent testing and deployment of code will eventually reduce risk levels within the project being worked on. Detecting bugs and other code defects will happen sooner in your SDLC. The easier, and sooner, these bugs and defects are found makes them easier and cheaper to fix. Feedback will be amplified and received faster, making communication smoother. | +| Better Communication | With a good CI process in place sharing code becomes easier. Code sharing means more visibility and collaboration between all members of your organization. | +| Faster Iterations | More frequent releases reduces the gap between the application in production and the one in development. A new way to develop features will most likely evolve thanks to every change being tested automatically. The visibility of changes will encourage your team to work in smaller batches, resulting in less assumptions allowing your to build features faster and more reliably. | +| Reduces Manual Testing | Human error is our number one enemy. Through old, not so well documented manual processes we allow the element of human error to exist within our organizations applications. Automated testing never gets tired or has an off day and therefore is highly reliable once the tests are in place. | +| Early Detection Prevention | Finding bugs and flaws sooner results in higher customer satisfaction and a major reduction in rework from fixing defects that make it to deployment. The earlier these defects are found the more trustworthy the process becomes. | diff --git a/docs/03.2_ci-with-actions.md b/docs/03.2_ci-with-actions.md new file mode 100644 index 0000000..e530f71 --- /dev/null +++ b/docs/03.2_ci-with-actions.md @@ -0,0 +1,25 @@ +## Using GitHub Actions for CI {docsify-ignore-all} + +github actions icon + +GitHub Actions offers workflow that can build the code in your repositories and run the associated tests. GitHub Actions gives you the flexibility to decide what events trigger a CI workflow. Maybe you desire a schedule or want to test every time code is pushed to your repositories, GitHub Actions can easily be configured to support these scenarios and more. + +Once your CI testing is complete, the results of each test will be reflected directly in the pull request. This gives you immediate visibility into the impact the current branch has on your code base. Branch protection rules can be configured which require some, or all, of your CI tests to pass prior to allowing pull requests to me merged. + +πŸ’‘GitHub-hosted runners come ready to work with your code right out of the box. Check out [the preinstalled software](https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners) available to use for your workflow! + +### Not sure where to start πŸ€·β€β™‚? + +continuous integration icon + +When you set up CI in your repository, GitHub analyzes the code in your repository and recommends CI workflows based on the language and framework in your repository. + +Using Node.js? GitHub will suggest a workflow template that installs all of your Node.js packages and executes your included tests. You can use this template as is or customize it to your own unique needs. This template is not required, and you are completely free to write your own custom workflow files to run your CI tests however you see fit! + +

+GitHub offers CI workflow templates for a variety of languages and frameworks. The complete list of CI workflow templates offered by GitHub is found in the actions/starter-workflows repository. +

+ +--- + +πŸ“–For more on [CI Using GitHub Actions](https://help.github.com/en/actions/building-and-testing-code-with-continuous-integration) checkout the official help documentation! diff --git a/docs/03.3_github-mobile-case-study.md b/docs/03.3_github-mobile-case-study.md new file mode 100644 index 0000000..a0eedd5 --- /dev/null +++ b/docs/03.3_github-mobile-case-study.md @@ -0,0 +1 @@ +# Case study about how GitHub uses action for mobile CI diff --git a/docs/03.4_some-other-case-study.md b/docs/03.4_some-other-case-study.md new file mode 100644 index 0000000..ad897af --- /dev/null +++ b/docs/03.4_some-other-case-study.md @@ -0,0 +1 @@ +another case study example, hopefully not GitHub related, of CI usage diff --git a/docs/03.5_ct-action.md b/docs/03.5_ct-action.md new file mode 100644 index 0000000..4a6b5b6 --- /dev/null +++ b/docs/03.5_ct-action.md @@ -0,0 +1,4 @@ +## Continuous Testing With Actions {docsify-ignore-all} + +# Exercise 4 - Creating a basic Continuous Testing Action +[continuous testing exercise](Exercises/04-Create-CT-Actions.md ':include') diff --git a/docs/03.6_security-scan.md b/docs/03.6_security-scan.md new file mode 100644 index 0000000..00c0437 --- /dev/null +++ b/docs/03.6_security-scan.md @@ -0,0 +1,4 @@ +## Security Scanning {docsify-ignore-all} + +# Exercise 5 - Creating GitHub Security Scan Actions +[exercise 5 security scan](Exercises/05-Create-Security-Scan.md ':include') diff --git a/docs/03.7_using-artifacts.md b/docs/03.7_using-artifacts.md new file mode 100644 index 0000000..9200306 --- /dev/null +++ b/docs/03.7_using-artifacts.md @@ -0,0 +1,7 @@ +## Using Artifacts In Actions {docsify-ignore-all} + +## Exercise 6 - Uploading and Downloading Artifacts in Actions +[exercise 6 upload and download artifacts](Exercises/06-Upload-Download-Artifacts.md ':include') + +## Exercise 6 A - Uploading and Downloading Artifacts with Artifactory in Actions +[exercise 6 upload and download artifacts with artifactory](Exercises/06.A-Upload-Download-Artifacts-%20from%20Artifactory.md ':include') diff --git a/docs/03.8_continuous-delivery.md b/docs/03.8_continuous-delivery.md new file mode 100644 index 0000000..c9cd1c3 --- /dev/null +++ b/docs/03.8_continuous-delivery.md @@ -0,0 +1,6 @@ +## Congratulations πŸŽ‰ {docsify-ignore-all} + +![Mona the Octocat celebrating](https://user-images.githubusercontent.com/38021615/78980948-bca77280-7ad3-11ea-8510-485acaa02a7e.png) + +Amazing job so far! Hopefully you are beginning to come up with ideas on how this all fits into your current project. Before we move into how GitHub Actions can be a Continuous Delivery (CD) solution, let's take those ideas and get the ball rolling on integrating them :smile: + diff --git a/docs/04.1_cd-overview.md b/docs/04.1_cd-overview.md new file mode 100644 index 0000000..27fdbdf --- /dev/null +++ b/docs/04.1_cd-overview.md @@ -0,0 +1,13 @@ +## CD From 30,000ft ✈️ {docsify-ignore-all} + +As we just learned, CI is the ability to quickly integrate many changes to a mainline and is often accompanied by some form of automated testing. The final step in a good CI pipeline is producing some sort of artifact, usually an application, that is ready to be packaged for some deployment. + +### This is where CD enters the scene + +The practice of taking that artifact and ensuring it is fully packaged and **delivered** to a pre-production environment is **Continuous Delivery**. + +CD allows get's your application to be "one click" deployed on whatever release schedule your project needs require. With that said, the benefits of CD are better realized if you get your changes into production as soon as possible. + +### But I want to deploy! + +As most of you know the next phase in any DevOps related pipeline is that of **Continuous Deployment**, which is the removed of that automated "one click" process in favor of an automated release process that places your changes into production without the need for humans! diff --git a/docs/04.2_cd-with-actions.md b/docs/04.2_cd-with-actions.md new file mode 100644 index 0000000..1250a8a --- /dev/null +++ b/docs/04.2_cd-with-actions.md @@ -0,0 +1,5 @@ +# CD With GitHub Actions {docsify-ignore-all} + +GitHub Actions supports delivery and deployment to cloud provider as well as self hosted environments. + +πŸ‘ˆWalkthrough the case-studies located in this section! diff --git a/docs/04.3_github-case-study.md b/docs/04.3_github-case-study.md new file mode 100644 index 0000000..bdc2f3d --- /dev/null +++ b/docs/04.3_github-case-study.md @@ -0,0 +1 @@ +Case study about how GitHub uses action for mobile CD diff --git a/docs/04.4_some-other-case-study.md b/docs/04.4_some-other-case-study.md new file mode 100644 index 0000000..cca6167 --- /dev/null +++ b/docs/04.4_some-other-case-study.md @@ -0,0 +1 @@ +some other CD case study diff --git a/docs/04.5_cd-action.md b/docs/04.5_cd-action.md new file mode 100644 index 0000000..25f9223 --- /dev/null +++ b/docs/04.5_cd-action.md @@ -0,0 +1,9 @@ +## Create Continuous Delivery Actions {docsify-ignore-all} +# Exercise 7 - Create CD Actions +[exercise 7](Exercises/07-Create-CD-Actions.md ':include') + +# Exercise 7 A - Deploy on push to `master` or `main` +[exercise 7](Exercises/07.A-Deploy-Prod.md ':include') + +# Exercise 7 B - Deploy a Release +[exercise 7](Exercises/07.B-Deploy-Release.md ':include') diff --git a/docs/04.6_exercise-8.md b/docs/04.6_exercise-8.md new file mode 100644 index 0000000..273d4d4 --- /dev/null +++ b/docs/04.6_exercise-8.md @@ -0,0 +1,13 @@ +## GitHub Script Actions {docsify-ignore-all} + +# Exercise 8 A - GitHub Script +[exercise 8 a](Exercises/08.A-GitHub-Script-Actions.md ':include') + +# Exercise 8 B - Deployment API +[exercise 8 b](Exercises/08.B-Add-Deployment-API.md ':include') + +# Exercise 8 C - Wait For Step +[exercise 8 c](Exercises/08.C-Add-Wait-For-Steps.md ':include') + +# Exercise 8 D - Splitting Jobs +[exercise 8 d](Exercises/08.D-Split-Jobs-for-Speed.md ':include') diff --git a/docs/04.7_on-to-actions.md b/docs/04.7_on-to-actions.md new file mode 100644 index 0000000..8daad72 --- /dev/null +++ b/docs/04.7_on-to-actions.md @@ -0,0 +1,14 @@ +## Congratulations πŸŽ‰ {docsify-ignore-all} + +![Mona the Octocat celebrating](https://user-images.githubusercontent.com/38021615/78980948-bca77280-7ad3-11ea-8510-485acaa02a7e.png) + +At this point we've covered quite a bit on using GitHub Actions to run custom workflows. Most of the tasks we've demonstrated up to this point are related directly to a CI/CD pipeline for software development. + +In the following sections we are going to answer these questions: + +- What if I can't find a community action that suits my needs? +- Is this feature only suitable for CI/CD? +- What can I do if I'm not able to consume open source code? +- I like to write code so how to I write actions? + +πŸ‘ˆLet's get started by moving to the **Anatomy of an Action** section. diff --git a/docs/05.1_action-overview.md b/docs/05.1_action-overview.md new file mode 100644 index 0000000..9fa5a80 --- /dev/null +++ b/docs/05.1_action-overview.md @@ -0,0 +1,72 @@ +## Anatomy of an action {docsify-ignore-all} + +![actions-anatomy](https://user-images.githubusercontent.com/6351798/82088922-df6b0f00-96af-11ea-88b1-bc95c34285b6.png) + +### Workflow recap + +If you recall, a workflow file is the **interface between you and the underlying actions** in use to accomplish your desired tasks. + +It is here where **you** supply inputs and consume outputs of an action. This is where the implementation details of the supplied information are abstracted away from you by the developer of the action. + +But what if you're the one who writes the action πŸ€”? + +### Writing custom actions + +**Why to write your own actions** + +- Compliance constraints: If you are unable to use open-source actions, or need to ensure your workflows fall within standards that you are bound to, writing your own actions ensures you stay in compliance while still making the most out of this feature. +- Stability needs: Some fear with community driven actions is that their development processes may not be thorough, the developers will introduce changes that break your workflow or they may just give up on the project when you desperately need a feature added to the action. It is good practice to vet any and all community actions before consuming them! +- Action doesn't exist yet: Sometimes actions that solve your problem don't exist just yet. Or if they do exist they don't provide the functionality you may need. +- Privacy is paramount: You have a highly custom, highly proprietary repository and you need to keep your workflow and other automation just as guarded. + +**The two types of actions** + +Currently there are two types of actions that exist: + +| JavaScript Actions | Docker Container Actions | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| | | + +**Location, location, location...** + +Great, you've decided you need or want to write a custom action and you've settle on the type of action that fits your needs best, **so where do you place the source code for your action?** + +This question comes down to two main factors: + +- Is this a public action that the community can use? +- Is this a private action used only by this repository? + +If your action is meant to be public then it is recommended that the source code for the action resides in a repository of its own. This allows for the action to be easily versioned and provides better discoverability to the GitHub community. + +If your action is meant to be private you can place it in any location within the repository you plan to use it in. GitHub recommends using the `.github` folder for this. For example `.github/action/my-custom-action` + +

+If you plan to publicly share your action, we recommend creating a README file to help people learn how to use your action.

+ +### Necessary files for custom actions + +Each action is a mixture of some key files. Each action you write **must** contain the following files: + +**Action metadata** +This file must be present for **both** JavaScript and Docker Container actions. It must be named `action.yml` or `action.yaml`. + +It is responsible for creating the interface between the source code of the action and the workflow file the end-user is going to fill it. + +We will talk in-depth about the action metadata file in a later section. + +**Action source code** + +This is the actual logic behind what you want your action to do. GitHub has created quite a few [development tools](https://github.com/actions/toolkit) to help with writing custom actions. It is not mandatory to use these tools if you want to create your own action, but they are nice to have πŸ˜„! + +**Dockerfile for Docker container actions only** + +If you have settled on writing a Docker container action, that action will require an accompanying Dockerfile. + +πŸ“–[More on writing a Dockerfile](https://docs.docker.com/engine/reference/builder/) + +

+Later, we will write one of each type of action to help demonstrate how these files work together.

+ +--- + +πŸ‘ˆ Before we dive more into writing our own actions, let's explore some examples of custom actions in use diff --git a/docs/05.2_action-type.md b/docs/05.2_action-type.md new file mode 100644 index 0000000..ca3dc59 --- /dev/null +++ b/docs/05.2_action-type.md @@ -0,0 +1,58 @@ +## Action Types {docsify-ignore-all} +GitHub Actions are open source repositories written in a [variety of languages](https://docs.github.com/en/actions/creating-actions/about-actions). + +### [Docker Actions](https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action) +Actions can be written with Dockerfiles so you can utilize any language and environment that your step needs. +Sample `action.yml` for a Docker action: + +``` +# action.yml +name: 'Hello World' +description: 'Greet someone and record the time' +inputs: + who-to-greet: # id of input + description: 'Who to greet' + required: true + default: 'World' +outputs: + time: # id of output + description: 'The time we greeted you' +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.who-to-greet }} +``` + +### [Node Actions](https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action) +Traditional Actions are written in Node. They can utilize any language that can compile in to Javascript, so many of them are written in Typescript and compiled into a `index.js` file. +GitHub provides [helper libraries](https://github.com/actions/toolkit) that allow you to interact with the Actions context and the GitHub API easily. + +### [Composite Actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-run-steps-action) +Finally you can now write Shell scripts and treat them like actions. +Sample `action.yml`: + +``` +name: 'Hello World' +description: 'Greet someone' +inputs: + who-to-greet: # id of input + description: 'Who to greet' + required: true + default: 'World' +outputs: + random-number: + description: "Random number" + value: ${{ steps.random-number-generator.outputs.random-id }} +runs: + using: "composite" + steps: + - run: echo Hello ${{ inputs.who-to-greet }}. + shell: bash + - id: random-number-generator + run: echo "::set-output name=random-id::$(echo $RANDOM)" + shell: bash + - run: ${{ github.action_path }}/goodbye.sh + shell: bash +``` + diff --git a/docs/05.4.1_inputs.md b/docs/05.4.1_inputs.md new file mode 100644 index 0000000..2b8f804 --- /dev/null +++ b/docs/05.4.1_inputs.md @@ -0,0 +1,52 @@ +## Inputs {docsify-ignore-all} + +This is an **optional** parameter used to allow workflows to define data the action will use at runtime. + +`action.yml` + +```yaml +inputs: + myfirstinput: + description: I should describe the purpose of the input here + required: false + default: this string is used when no value is supplied in a workflow +``` + +In the example above **myfirstinput** is the name of the input. We see that it contains a description, whether or not it is required, and what the default value is for the input. + +Adding more than one input to an `action.yml` file is quite easy. + +`action.yml` + +```yaml +inputs: + myfirstinput: + description: I should describe the purpose of the input here + required: false + default: this string is used when no value is supplied in a workflow + mysecondinput: + description: some other description about this input + required: true +``` + +Since **mysecondinput** is required we don't have to give it a default value. This action will fail to run if the second parameter isn't supplied in the workflow. Speaking of workflows, let's see how to make sure we are supplying input to an action when it expects it. + +We will use the `action.yml` input metadata that we defined above for this example. + +`workflow.yml` + +```yaml +jobs: + my_first_job: + name: My Job Name + steps: + - uses: our/custom-action@v1 + with: + mysecondinput: {{secrets.SOME_REQUIRED_SECRET}} +``` + +πŸ€”Interesting! We simply use the `uses` keyword in the `workflow` file to specify that we are passing data as input to the desired action. In our example, since `myfirstinput` wasn't required we chose to not supply it with a value. This results in the default value being used. However we did supply a value for `mysecondinput` since it is a required input and has no default value. + +

+Although most actions supply example on how to use them in their README file, some option may not be immediately documented. You can ALWAYS find what values and action expects or allows by reading the `action.yml` file for that action. This is a good habit to get into +

diff --git a/docs/05.4.2_outputs.md b/docs/05.4.2_outputs.md new file mode 100644 index 0000000..5db790a --- /dev/null +++ b/docs/05.4.2_outputs.md @@ -0,0 +1,50 @@ +## Outputs {docsify-ignore-all} + +This is an **optional** parameter used when your action needs to pass data to another action later in the workflow. Consider an action that makes a specific HTTP request and needs to send the response of that request to an operation later in the workflow chain. This is where **outputs** come into play. + +Like **Inputs** the **outputs**of an action get declared in the `action.yml` like below: + +`action.yml` + +```yaml +outputs: + res: + description: response object from super fancy HTTP request +``` + +**outputs** get named, in the above scenario that name is `res` and they have one parameter which is `description`. + +As you expect, actions can have more than one output and defining them is as easy as adding to the **outputs** block. + +`action.yml` + +```yaml +outputs: + res: + description: response object from super fancy HTTP request + anotheroutput: + description: see, you really can use more than one output +``` + +

+description is required if you plan to define outputs for your action. +

+ +Let's take a look πŸ‘€at how to use **outputs** from the workflow side of things. + +`workflow.yml` + +```yaml +steps: + - name: My first step + uses: our/custom-action@v1 + id: step1 + - name: My backup step + uses: any/action-expecting-input@v1 + with: + expectedinput: ${{steps.step1.outputs.res}} +``` + +Take notice that the `expectedinput` uses a specific output named `res`. It was in the `action.yml` file that `res` was defined. So like **inputs**, we can check the `action.yml` file for any given action to see what kind of outputs this action is capable of passing down throughout your workflows. + +πŸ‘ˆContinue to learn about the Entrypoint requirement in the `action.yml` file! diff --git a/docs/05.4.3_entrypoint.md b/docs/05.4.3_entrypoint.md new file mode 100644 index 0000000..85a370c --- /dev/null +++ b/docs/05.4.3_entrypoint.md @@ -0,0 +1,66 @@ +## Entrypoint {docsify-ignore-all} + +The final **required** piece of any actions metadata is the entrypoint which is defined by the **runs** keyword. The main purpose of the entrypoint is to define which application the actions code will be executed with as well as the path to the actions source code. Other parameters are available for use in the **runs** block of the `action.yml` metadata file. These parameters vary depending on the type of action you are writing. + +### JavaScript Actions + +When writing custom JavaScript actions the **runs** keyword has three parameters available to it: + +- **using:** A **required** parameter defining the application to be used to execute the code. +- **main:** A **required** parameter defining the file, including path, containing the code to be executed. +- **env:** An **optional** parameter defining a key/value map of environment variables to be set inside the runners virtual environment. + +`action.yml` + +```yaml +runs: + using: "node12" + main: "build/index.js" + env: + somevar: "some value" +``` + +### Docker Container Actions + +Docker container actions have a different set of parameter available to the **runs** keyword. + +- **using:** A **required** parameter that **must** be set to `docker` +- **image:** A **required** parameter specifying the docker images to create a container from. This value can either be the base image name to an existing Docker container or a `Dockerfile` located in the repository. +- **env:** An **optional** parameter defining a key/value map of environment variables to be set inside the container environment. +- **entrypoint:** An **optional** parameter to override the Docker `ENTRYPOINT` specified in a `Dockerfile`. This value also sets a value if one was not already specified. [**Dockerfile support for GitHub Actions**](https://help.github.com/en/actions/building-actions/dockerfile-support-for-github-actions/#entrypoint). +- **args:** An **Optional** parameter defining an array of strings that define the inputs for a Docker container. Inputs can include hardcoded strings. GitHub passes the args to the container's `ENTRYPOINT` when the container starts up. + +
+ +The args are used in place of the CMD instruction in a Dockerfile. If you use CMD in your Dockerfile, use the guidelines ordered by preference: + +1. Document required arguments in the action's README and omit them from the CMD instruction. +1. Use defaults that allow using the action without specifying any args. +1. If the action exposes a - -help flag, or something similar, use that to make your action self-documenting. +1. If you need to pass environment variables into an action, make sure your action runs a command shell to perform variable substitution. For example, if your ENTRYPOINT attribute is set to "sh -c", args will be run in a command shell. Alternatively, if your Dockerfile uses an ENTRYPOINT to run the same command ("sh -c"), args will execute in a command shell. + +
+ +`action.yml` + +```yaml +runs: + using: 'docker' + image: 'Dockerfile' + args: + - 'foo' + - 'bar' + +OR + +runs: + using: 'docker' + image: 'docker://nginx:latest' + args: + - ${{inputs.some_defined_input}} +``` + +

+Along with the keywords we covered, you can also supply branding to any actions you create. Branding an action is outside of our scope for detailed coverage, if you wish to learn more visit the documentation on branding. + +πŸ‘ˆContinue to learn more about the runner environment! diff --git a/docs/05.4_action-metadata.md b/docs/05.4_action-metadata.md new file mode 100644 index 0000000..6fcea37 --- /dev/null +++ b/docs/05.4_action-metadata.md @@ -0,0 +1,17 @@ +## Action Metadata {docsify-ignore-all} + +As we've mentioned before, the `action.yml` sits between the source code of the action and the workflow used to consume the action. + +

+ How the metadata fits with the other pieces of an action +

+ +### Purpose of the metadata + +This file defines three major attributes for any action: + +

+ Three major components defined by action.yml +

+ +πŸ‘ˆLet's explore each of these attributes in more detail! diff --git a/docs/05.5_action-runner-env.md b/docs/05.5_action-runner-env.md new file mode 100644 index 0000000..9a49b8b --- /dev/null +++ b/docs/05.5_action-runner-env.md @@ -0,0 +1,25 @@ +## What's in a runner? {docsify-ignore-all} + +GitHub-hosted runners are virtual machines provided to you that execute your workflows. These machines grant you administrative privileges regardless of the operating system you are running on. This includes using `sudo` without a password for Mac and Linux machines. + +**Runner Hardware** + +| CPU | RAM | Storage | +| ------ | --- | -------- | +| 2 core | 7GB | 14GB SSD | + +**Runner Operating Systems** + +- Windows Server 2019 +- Ubuntu 20.04 +- Ubuntu 18.04 +- Ubuntu 16.04 +- macOS Catalina 10.15 + +**Environment Variables** + +A wide range of environment variables are included in each runner. It is recommended to use these environment variables if possible for a more consistent experience. + +These variables are available to every step in a workflow run and steps are capable of reading, creating, or modifying environment variables. + +[Explore more about environment variables](https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables) diff --git a/docs/05.5b_self-hosted-runners.md b/docs/05.5b_self-hosted-runners.md new file mode 100644 index 0000000..155ab83 --- /dev/null +++ b/docs/05.5b_self-hosted-runners.md @@ -0,0 +1,98 @@ +## A Focus on Self-Hosted Runners + +You've learned what runners are and how they are structured in the GitHub cloud environment. In this section, we'll help you discern whether a self-hosted runner is the right choice for your project or organization. You'll learn about scaling considerations and configuration scenarios. We'll also cover some points to help you troubleshoot your runner. + +## Choosing to Host a Runner on Your Hardware + +"When should I decide for a self-hosted runner?" There are a number of factors to consider. The first is the flexibility offered to optimize the runner. + +### Optimization Flexibility + +Although cloud-based runners offer ease of use, there is a level of flexibility and optimization that only self-hosted runners are better able to provide. They run on your hardware. So, you have full control within your infrastructure, breaking you free from the limitations on performance and configuration encountered with cloud-based runners. You are able to allot the desired amount of hardware resources to each runner. In contrast, a cloud-based runner will have a fixed configuration and require the assistance of a GitHub support team when the time comes to perform any updates or tweaking. + +### Access Control + +Another reason to opt for self-hosted runners is that they enable you to customize access to your runners. A cloud-hosted runner runs on a repository level. In contrast, runners on your hardware can be configured for access and use on a variety of levels that we cover in this topic. + +## Technical Considerations for Setting Up a Runner + +#### Hardware Requirements + +For optimal performance, there are some minimal requirements that you will want to have in place: + +- A minimum of 4 vCPUs are necessary for installation +- Make sure that your hardware has any required software installed, including runner dependencies and dependencies for any actions used. Install the following: + + - **Node.js** to enable JavaScript actions. + - **Docker** to facilitate container actions. + +#### Service Configuration to Ensure Runner Availability + +For times when you need to restart the hardware on which your runner lives, you will probably also want your runner to restart automatically. Configure your runner as a service to ensure that machines come back online after a hardware restart. + +Refer to the [GitHub documentation > Configuring the self-hosted runner application as a service ](https://docs.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service) to learn how to configure your runner as a service. + +#### Security + +Do not use self-hosted runners in public repos as malicious code submitted through a pull request could be run. + +## Configuring Access Control + +As previously mentioned, hosting runners on your hardware allows you to group several runners and control access to them on several levels. Controlling access ensures the consistent availability of runners only to the teams or users to which you have assigned them. + +There are a number of configuration options in place to control access: + +#### Access Level Assignment + +You can take advantage of a a wide range of granularity to configure access to runners or runner groups. First, there are various levels at which you can assign runner visibility. These are: + +- #### Enterprise Level + + Register your runner at the enterprise level to share across all of the organizations of an enterprise. + +- #### Organizational Level + + Some repositories are shared across an organization. Register your runner on an organizational level to make it available only to that specific organization across all of its repositories. + +- #### Repository Level + You can make runners accessible only to certain repositories. + +## Grouping Runners + +Grouping refers to organizing your runners into groups. Runners that are registered on an enterprise or organizational level can be organized into pools. Access is then granted to or restricted for a specific user or group of users to a certain group of runners. Designate which organizations in the enterprise can use the runners in the group. Specify which repositories inside of an organization can use a group of runners. + +##### Here's an example: + +![diagram: "Workflow" on left, with one arrow pointing to "Jobs". "Jobs" has one arrow pointing to "Job 1", and another arrow pointing to "Job 2". "Job 1" points to "Runner 1", which points to "Destroy 1". "Job 2" points to "Runner 2", which points to "Destroy 2". ](images/gh-actions-runner-lc.png) + +##### Which problem does runner grouping solve? + +It ensures that access is available to a group of runners specifically for teams or employees whose use of the runner has priority. + +## Labelling Runners + +In the same way individual runners can receive labels, so can runner groups. + +### Custom Label Assignment + +In addition to the labels that GitHub assigns to runners, administrators can add customer labels to the runners they create. These labels enable the runner to be targeted at runtime. + +For the technical specifics on setting up your custom labels, refer to [GitHub documentation - Creating a custom label.](https://docs.github.com/en/actions/hosting-your-own-runners/using-labels-with-self-hosted-runners#creating-a-custom-label) + +## Troubleshooting Your Runner + +### The `_diag` Directory + +If you are experiencing any issue with your runner, a starting point for troubleshooting is the `_diag` directory. This location contains log files that you should examine for indications of what has failed. + +> Note: This directory may not be immediately available until the system produces logs; at which point the system creates the folder. + +### Check for Stray Artifacts + +It is important to note that there are times that a runner may not be in a clean state. This means that artifacts from previous builds could still exist in your working directory and interfere with new builds. Be aware of any stray, leftover artifacts if your build relies on caching. + +## References + +[The GitHub Runner Repository](https://github.com/actions/runner) + +[Documentation: Adding Self-Hosted Runners](https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners) diff --git a/docs/05.6_custom-action.md b/docs/05.6_custom-action.md new file mode 100644 index 0000000..3a5b87b --- /dev/null +++ b/docs/05.6_custom-action.md @@ -0,0 +1,131 @@ +# Toolkits, tips, tricks for writing custom actions {docsify-ignore-all} + +## JavaScript actions library + +When writing JavaScript based actions it is incredibly useful to leverage the [GitHub Actions toolkit](https://github.com/actions/toolkit). This toolkit comes packed with functions to perform a wide range of tasks. + + + +#### **core** + +Useful when managing inputs, outputs, results, logging, secrets and variables. + +Installation: `npm install @actions/core --save` + +#### **exec** + +Allows execution of CLI tools and is capable of processing the output. + +Installation: `npm install @actions/exec --save` + +#### **glob** + +Provides a set of functions that make searching for files matching a glob patterns easy to use. + +Installation: `npm install @actions/glob --save` + +#### **io** + +Need to perform disk related tasks such as copying, moving or deleting files? If so, this is the package for you. + +Installation: `npm install @actions/io --save` + +#### **tool-cache** + +Provides functions for downloading and caching tools. + +Installation: `npm install @actions/tool-cache --save` + +#### **github** + +If interaction with your repo through the GitHub API is likely, this package provides you will an Octokit client that is fully hydrated to the current action context. + +Installation: `npm install @actions/github --save` + +#### **artifact** + +Provides functions that interact with artifacts. + +Installation: `npm install @actions/artifact --save` + + + +## Workflow commands for GitHub Actions + +If you are running shell commands or writing a Docker container action there is a set of workflow commands available to you. These commands can be a part of your `workflow.yml` files or source code in your custom actions. + +Each function in the `@actions/core` tookit package has an equivalent workflow command. Let's look at how them map together now: + +| Toolkit function | Equivalent workflow command | +| ------------------- | --------------------------------------------------- | +| core.addPath | add-path | +| core.debug | debug | +| core.error | error | +| core.endGroup | endgroup | +| core.exportVariable | set-env | +| core.getInput | Accessible using environment variable INPUT\_{NAME} | +| core.getState | Accessible using environment variable STATE\_{NAME} | +| core.isDebug | Accessible using environment variable RUNNER_DEBUG | +| core.saveState | save-state | +| core.setFailed | Used as a shortcut for ::error and exit 1 | +| core.setOutput | set-output | +| core.setSecret | add-mask | +| core.startGroup | group | +| core.warning | warning fil | + +**Using these commands in a workflow** + +```yaml +- name: Set selected color + run: echo '::set-env name=USER_NAME::Mona' +- name: Get color + run: echo 'The selected color is' $USER_NAME +``` + +**Using commands as a part of a Python based Docker container action** + +```python +def select_random_fact(fact_arr): + return fact_arr[random.randint(0, len(fact_list)+1)] + + +random_fact = select_random_fact(fact_list) + +# Set the output of the action as the value of random_fact +print(f"::set-output name=fact::{random_fact}") +``` + +### GitHub Script + +A really useful action that exists is called [GitHub Script](https://github.com/actions/github-script) and its main purpose is to allow you to use the GitHub API through Octokit directly in your workflow files without the need to package and manage a complete custom action. + +Take a look at this quick example of using GitHub Script + +```yaml +on: + issues: { types: opened } + +jobs: + comment: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@0.9.0 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'πŸ‘‹ Thanks for reporting!' + }) +``` + +At first glance it may seem as though a workflow files accepts the Octokit JavaScript library. It is important to note that this **is not** the case, and rather you are passing raw text to an action located at `actions/github-script@0.9.0`. + +

+It's also worth noting that this action is under active development and many things can change, so use at your own risk. We will show you this action in action... pun intended, regardless of it's development state.

+ +--- + +πŸ‘ˆ Enough talk, let's get our hands... or keyboards rather... dirty! diff --git a/docs/05.7_exercise-9.md b/docs/05.7_exercise-9.md new file mode 100644 index 0000000..d91eca7 --- /dev/null +++ b/docs/05.7_exercise-9.md @@ -0,0 +1,4 @@ +## Writing Custom Actions {docsify-ignore-all} +# Exercise 9 - Create New Repository +[exercise 9](Exercises/09-Create-New-Repo-To-Pull-In-Container.md ':include') + diff --git a/docs/06.0_Summary.md b/docs/06.0_Summary.md new file mode 100644 index 0000000..c52ef9e --- /dev/null +++ b/docs/06.0_Summary.md @@ -0,0 +1,16 @@ +## Summary {docsify-ignore-all} + +Over the last few hours we've covered a wide range of topics around using GitHub Actions. Let's take a moment to do a quick recap on what we learned: + +- Configure workflows within your repositories +- Implement continuous integration using GitHub Actions +- Implement continuous delivery using GitHub Actions +- Write custom JavaScript actions +- Write custom Docker container actions +- Publish applications to cloud providers +- Share actions across workflows and repositories +- Publish actions to the GitHub marketplace + +### Next steps πŸŽ‰ + +Let's take what we know and apply it to the project we've been planning around! diff --git a/docs/Exercises/01-Create-Dockerfile.md b/docs/Exercises/01-Create-Dockerfile.md new file mode 100644 index 0000000..9942297 --- /dev/null +++ b/docs/Exercises/01-Create-Dockerfile.md @@ -0,0 +1,88 @@ +# Create the dockerfile + +In this session, we are going to be deploying an application within a **Docker** container. Before we can deploy our app, we need to begin setting up a foundation to make changes to. + +## Exercise: Add Dockerfile + +1. Create a new branch called `Docker` +1. In the root of the repository, create a new file named: `Dockerfile` +1. Copy and paste the following code snippet into the new file: + + > **:warning: NOTE:** Update the **orgname** and **reponame** variables to your organization and repository names. + + ```Dockerfile + ######################################### + ######################################### + ### Dockerfile to run some Some Build ### + ######################################### + ######################################### + + # This is a copy of the GitHub Action runner + FROM myoung34/github-runner:latest + + ######################################### + # Variables # + ######################################### + ARG orgname="organization name" + ARG reponame="repository name" + + ######################################### + # Label the instance and set maintainer # + ######################################### + LABEL com.github.actions.name="Some Image" \ + com.github.actions.description="Its a build image" \ + com.github.actions.icon="code" \ + com.github.actions.color="red" \ + maintainer="GitHub DevOps " \ + org.opencontainers.image.authors="GitHub DevOps " \ + org.opencontainers.image.url="https://github.com/${orgname}/${reponame}" \ + org.opencontainers.image.source="https://github.com/${orgname}/${reponame}" \ + org.opencontainers.image.documentation="https://github.com/${orgname}/${reponame}" \ + org.opencontainers.image.vendor="GitHub" \ + org.opencontainers.image.description="Its a build image" + + ######################################## + # Copy dependencies files to container # + ######################################## + COPY dependencies/* / + + # ################################ + # # Installs python dependencies # + # ################################ + # RUN pip3 install --no-cache-dir pipenv + # # Bug in hadolint thinks pipenv is pip + # # hadolint ignore=DL3042 + # RUN pipenv install --clear --system + + # #################### + # # Run NPM Installs # + # #################### + # RUN npm config set package-lock false \ + # && npm config set loglevel error \ + # && npm --no-cache install + # # Add node packages to path + # ENV PATH="/node_modules/.bin:${PATH}" + + # ############################## + # # Installs ruby dependencies # + # ############################## + # RUN bundle install + + ###################### + # Make the directory # + ###################### + RUN mkdir -p /action/lib + + ############################# + # Copy scripts to container # + ############################# + COPY library /action/lib + + ###################### + # Set the entrypoint # + ###################### + ENTRYPOINT ["/action/lib/entrypoint.sh"] + ``` + +1. Commit the file. +1. Open a pull request and merge the `Docker` branch into the `main` branch. diff --git a/docs/Exercises/02-Create-CI-Action.md b/docs/Exercises/02-Create-CI-Action.md new file mode 100644 index 0000000..009f576 --- /dev/null +++ b/docs/Exercises/02-Create-CI-Action.md @@ -0,0 +1,113 @@ +# Creating basic CI Github Action + +This exercise will walk you through setting up *Continuous Integration* on your current repository. +The objective of *Continuous Integration* is to achieve constant feedback on your changes to your code base and begin the process of testing and deploying your code base. + +**GitHub Actions** run off of workflow files that are managed and maintained in your repository. The first action we are going to "install" on our repository uses an open source Action called [Docker Build](https://github.com/docker/build-push-action). This action will try to build the current `Dockerfile` and see if it compiles successfully. + +## Step 1: Add a GitHub Action workflow file + +1. Create a new branch of code called `CI` +1. Create a new file named `.github/workflows/ci.yml` +1. Copy the code below to the newly created file: + + ```yaml + --- + ######## + ######## + ## CI ## + ######## + ######## + name: Continuous Integration + + # + # Documentation: + # https://help.github.com/en/articles/workflow-syntax-for-github-actions + # + + ############################# + # Start the job on all push # + ############################# + # Don't need to run on push to master/main + on: + push: + branches-ignore: + - 'master' + - 'main' + + ############### + # Set the Job # + ############### + jobs: + build: + # Name the Job + name: CI + # Set the agent to run on + runs-on: ubuntu-latest + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v2 + + ######################## + # Setup Docker build X # + ######################## + - name: Setup BuildX + uses: docker/setup-buildx-action@v1 + + ############################## + # Build the docker container # + ############################## + - name: Build Docker container + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + build-args: | + BUILD_DATE=${{ env.BUILD_DATE }} + BUILD_REVISION=${{ github.sha }} + BUILD_VERSION=${{ github.sha }} + push: false + ``` + +1. Commit the file. + +This workflow file is set up to run when a push is made to branches in the repository, unless they are pushed to the `main` or `master` branch. This is controlled by this section of the code: + +```yaml + push: + branches-ignore: + - 'master' + - 'main' +``` + +When we push a change to a branch, the GitHub Action will clone the repository code base, and run the docker build against the changes. + +## Step 2: Running your GitHub Action + +1. Open a pull request with the `CI` branch into the `main` branch. + + In the pull request, you will see the GitHub Actions job running and its results. You can review the logs of the run and the steps it took by clicking on **Details** next to the GitHub Action. You can experiment with this Action, but making additional updates to the code and committing it. + +1. Merge the pull request. + +## Step 3: Add branch protection rules + +The last two pull requests we created and merged, were able to be merged without a required review. While this might work for this training repository, it doesn't scale well in the real world with business critical systems. Through the use of protected branches, we can enforce required reviews on pull requests to specific branches on our repository. + +To protect our main branch and require at least one review and a passing test, perform the following: + +1. On GitHub, navigate to the main page of the repository. +1. Under your repository name, click **Settings**. +1. In the left menu, click **Branches**. +1. Next to "Branch protection rules", click **Add rule**. +1. Under "Branch name pattern", type `main`. +1. Select the **Require pull request reviews before merging** checkbox. +1. Select the **Require status checks to pass before merging** checkbox. +1. Search for **CI** in the Status checks found in the last week for this repository. +1. Click **Save changes**. diff --git a/docs/Exercises/02.A-Create-QA-Branch.md b/docs/Exercises/02.A-Create-QA-Branch.md new file mode 100644 index 0000000..d53b38f --- /dev/null +++ b/docs/Exercises/02.A-Create-QA-Branch.md @@ -0,0 +1,22 @@ +# Creating additional protected branches + +Many companies follow different models of deployment and git flow. Some only require the simple **GitHub** flow, while others use a more legacy git flow. +If you follow more of the [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/), you will likely need to create additional protected branches like `DEV`, `QA`, or `PROD`. + +![gitflow](https://user-images.githubusercontent.com/38323656/102368103-1c69ed80-3f80-11eb-9353-586432ec0678.png) +> An example workflow which adopts the Git Flow branching strategy + +Once you have set up those branch protections, you can then use them later on to help trigger additional workflows and flags. + +To protect our new branch(es) and require at least one review and a passing test, perform the following: + +1. On GitHub, navigate to the main page of the repository. +1. Under your repository name, click **Settings**. +1. In the left menu, click **Branches**. +1. Next to "Branch protection rules", click **Add rule**. +1. Under "Branch name pattern", type `DEV` or `QA` or `PROD`. +1. Select the **Require pull request reviews before merging** checkbox. +1. Select the **Require status checks to pass before merging** checkbox. +1. Select the **Continuous Integration** checkbox in the Status checks found in the last week for this repository. +1. Click **Save changes**. +1. Repeat for all branches you wish to protect. diff --git a/docs/Exercises/02.B-Create-Context-Job.md b/docs/Exercises/02.B-Create-Context-Job.md new file mode 100644 index 0000000..27d95f5 --- /dev/null +++ b/docs/Exercises/02.B-Create-Context-Job.md @@ -0,0 +1,62 @@ +# GitHub Context + +**GitHub Actions** store information about the job, environment, and other aspects of the jobs contexts. + +See the [documentation](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) for context details. + +Once the job runs, you will be able to see all variables of the job, and what could be available to you. +This is helpful to debug environments and see what variables are available to you. +You could then copy this code into another running workflow and see the output that is generated by that job. + +1. Create a branch called `context-job` +1. Create a file, `.github/workflows/context.yml` +1. Copy the following code: + + > **:warning: Note:** This job is primarily used for debugging, or helping the user to find variable information stored in a running job. + + ```yaml + # This is a basic workflow to help you get started with Actions + + name: Context Info + + # Controls when the action will run. + on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches-ignore: main + + # A workflow run is made up of one or more jobs that can run sequentially or in parallel + jobs: + Context-Info: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + - name: Dump job context + env: + JOB_CONTEXT: ${{ toJson(job) }} + run: echo "$JOB_CONTEXT" + - name: Dump steps context + env: + STEPS_CONTEXT: ${{ toJson(steps) }} + run: echo "$STEPS_CONTEXT" + - name: Dump runner context + env: + RUNNER_CONTEXT: ${{ toJson(runner) }} + run: echo "$RUNNER_CONTEXT" + - name: Dump strategy context + env: + STRATEGY_CONTEXT: ${{ toJson(strategy) }} + run: echo "$STRATEGY_CONTEXT" + - name: Dump matrix context + env: + MATRIX_CONTEXT: ${{ toJson(matrix) }} + run: echo "$MATRIX_CONTEXT" + ``` + +1. Open a pull request and merge the `context-job` branch into the `main` branch. diff --git a/docs/Exercises/02.C-Create-Manual-Job.md b/docs/Exercises/02.C-Create-Manual-Job.md new file mode 100644 index 0000000..f2a35e7 --- /dev/null +++ b/docs/Exercises/02.C-Create-Manual-Job.md @@ -0,0 +1,41 @@ +# GitHub Manual Job + +**GitHub Actions** allows you to be able to run manual jobs and pass the job inputs. + +This allows the user to be able to set up jobs that run when they want to manually initiate them, and pass variables needed to complete the job. +This gives the users more flexability on how they could semi-automate the deploy/release process. + +1. Create a branch called `manual-job` +1. Create a file, `.github/workflows/manual-deployment.yml` +1. Copy the following code: + +> **:warning: Note:** This job is primarily used for manual triggers. + +```yaml +# This is a basic workflow to help you get started with Actions +name: Manual Deployment + +# Set the job to run manually +on: + workflow_dispatch: + # Set the input variables you want to pull in + inputs: + branch: + description: 'Branch to deploy' + required: true + default: 'Dev' + app_list: + description: 'Comma separated list of apps to deploy' + required: true + default: 'App1,App2' + +jobs: + Deploy_Apps: + runs-on: ubuntu-latest + steps: + - run: | + echo "Running deployment of branch ${{ github.event.inputs.branch }}!" + echo "- Deploying the following Apps: ${{ github.event.inputs.app_list }}!" +``` + +1. Open a pull request and merge the `manual-job` branch into the `main` branch. diff --git a/docs/Exercises/03-Create-Dependabot-Config.md b/docs/Exercises/03-Create-Dependabot-Config.md new file mode 100644 index 0000000..e04998f --- /dev/null +++ b/docs/Exercises/03-Create-Dependabot-Config.md @@ -0,0 +1,60 @@ +# Configure Dependabot + +In this session, we are going to be deploying [Dependabot](https://dependabot.com/) to your **GitHub Actions**. This is a built in tool inside **GitHub** that will help validate your code is up to date and free of known CVE's. + +### Exercise: Add Dependabot config + +1. Create a new branch called `Dependabot` +1. Go to your repository, click on **Settings** +1. On the left sidebar, click on **Security & Analysis** +1. Click **Enable** on `Dependabot Security Updates` +1. In the repository, create a new file named: `.github/dependabot.yml` +1. Copy and paste the following code snippet into the new file: + + ```yaml + ################################# + # GitHub Dependabot Config info # + ################################# + version: 2 + updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + + # Maintain dependencies for docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + + # Maintain dependencies for python with pip + - package-ecosystem: "pip" + directory: "/dependencies" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + + # Maintain dependencies for js with npm + - package-ecosystem: "npm" + directory: "/dependencies" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + + # Maintain dependencies for ruby with bundler + - package-ecosystem: "bundler" + directory: "/dependencies" + schedule: + interval: "daily" + open-pull-requests-limit: 10 + ``` + +1. Commit the file. +1. Open a pull request and merge the `Dependabot` branch into the `main` branch. + +## Links + +- [Dependabot configuration](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates) diff --git a/docs/Exercises/03.A-Lock-Dependencies.md b/docs/Exercises/03.A-Lock-Dependencies.md new file mode 100644 index 0000000..9fa0e14 --- /dev/null +++ b/docs/Exercises/03.A-Lock-Dependencies.md @@ -0,0 +1,518 @@ +# Locking your dependencies + +It is critical to lock your dependencies in your code base. This allows **Dependabot** to parse the currently installed versions, and check for known issues. +This also is a great code practice as it allows users to be able to build the code at the same point it was generated. This will allow for more consistent builds and less issues with versioning in the future. + +## Exercise: Add package lock files + +Depending on the language you choose, you will need to add a lock file to help. + +--- + +### PIP Add the Pipfile.lock + +- Create a branch called `Deps` +- Add the following file to your repository: `/dependencies/Pipfile.lock`: + +
+ Click here to copy the file + +```json +{ + "_meta": { + "hash": { + "sha256": "248e90964ec6432847db5bf54d04b48bba8126e1379315369ea608cc5aa57743" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.5" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "django": { + "hashes": [ + "sha256:558cb27930defd9a6042133258caf797b2d1dee233959f537e3dc475cb49bd7c", + "sha256:cf5370a4d7765a9dd6d42a7b96b53c74f9446cd38209211304b210fe0404b861" + ], + "index": "pypi", + "version": "==2.2.17" + }, + "django-cors-middleware": { + "hashes": [ + "sha256:5bbdea85e22909d596e26f6e0dbc174d5521429fa3943ae02a2c6c48e76c88c7", + "sha256:856dbe4d7aae65844ccc68acb49c6da7dbf7cbacaf5bcf37019f4c0c60b3be84" + ], + "index": "pypi", + "version": "==1.5.0" + }, + "django-extensions": { + "hashes": [ + "sha256:7cd002495ff0a0e5eb6cdd6be759600905b4e4079232ea27618fc46bdd853651", + "sha256:c7f88625a53f631745d4f2bef9ec4dcb999ed59476393bdbbe99db8596778846" + ], + "index": "pypi", + "version": "==3.1.0" + }, + "djangorestframework": { + "hashes": [ + "sha256:0209bafcb7b5010fdfec784034f059d512256424de2a0f084cb82b096d6dd6a7" + ], + "index": "pypi", + "version": "==3.12.2" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "index": "pypi", + "version": "==1.7.1" + }, + "pytz": { + "hashes": [ + "sha256:3e6b7dd2d1e0a59084bcee14a17af60c5c562cdc16d828e8eba2e683d3a7e268", + "sha256:5c55e189b682d420be27c6995ba6edce0c0a77dd67bfbe2ae6607134d5851ffd" + ], + "version": "==2020.4" + }, + "six": { + "hashes": [ + "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", + "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" + ], + "index": "pypi", + "version": "==1.15.0" + }, + "sqlparse": { + "hashes": [ + "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0", + "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8" + ], + "markers": "python_version >= '3.5'", + "version": "==0.4.1" + } + }, + "develop": {} +} +``` + +
+ +- Commit the code +- Open Pull request + +--- + +### NPM Add the package-lock.json + +- Create a branch called `Deps` +- Add the following file to your repository: `/dependencies/package-lock.json`: + +
Click here to copy the file + +```json +{ + "name": "demo-action", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "requires": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==" + }, + "jsonlint": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.3.tgz", + "integrity": "sha512-jMVTMzP+7gU/IyC6hvKyWpUU8tmTkK5b3BPNuMI9U8Sit+YAWLlZwB6Y6YrdCxfg2kNz05p3XY3Bmm4m26Nv3A==", + "requires": { + "JSV": "^4.0.x", + "nomnom": "^1.5.x" + } + }, + "linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash.differencewith": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz", + "integrity": "sha1-uvr7yRi1UVTheRdqALsK76rIVLc=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "markdown-it": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.2.tgz", + "integrity": "sha512-4Lkvjbv2kK+moL9TbeV+6/NHx+1Q+R/NIdUlFlkqkkzUcTod4uiyTJRiBidKR9qXSdkNFkgv+AELY8KN9vSgVA==", + "requires": { + "argparse": "^2.0.1", + "entities": "~2.0.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + } + } + }, + "markdownlint": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.22.0.tgz", + "integrity": "sha512-J4B+iMc12pOdp/wfYi03W2qfAfEyiZzq3qvQh/8vOMNU8vXYY6Jg440EY7dWTBCqROhb1i4nAn3BTByJ5kdx1w==", + "requires": { + "markdown-it": "12.0.2" + } + }, + "markdownlint-cli": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.26.0.tgz", + "integrity": "sha512-biLfeGNZG9nw0yJbtFBzRlew2/P5w7JSseKwolSox3zejs7dLpGvPgqbC+iqJnqqGWcWLtXaXh8bBEKWmfl10A==", + "requires": { + "commander": "~6.2.1", + "deep-extend": "~0.6.0", + "get-stdin": "~8.0.0", + "glob": "~7.1.6", + "ignore": "~5.1.8", + "js-yaml": "~3.14.1", + "jsonc-parser": "~3.0.0", + "lodash.differencewith": "~4.5.0", + "lodash.flatten": "~4.4.0", + "markdownlint": "~0.22.0", + "markdownlint-rule-helpers": "~0.13.0", + "minimatch": "~3.0.4", + "minimist": "~1.2.5", + "rc": "~1.2.8" + } + }, + "markdownlint-rule-helpers": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.13.0.tgz", + "integrity": "sha512-rRY0itbcHG4e+ntz0bbY3AIceSJMKS0TafEMgEtKVHRZ54/JUSy6/4ypCL618RlJvYRej+xMLxX5nkJqIeTZaQ==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "requires": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "prettyjson": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", + "integrity": "sha1-/P+rQdGcq0365eV15kJGYZsS0ok=", + "requires": { + "colors": "^1.1.2", + "minimist": "^1.2.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} +``` + +
+ +- Commit the code +- Open Pull request + +--- + +### RUBY Add the gemfile.lock + +- Create a branch called `Deps` +- Add the following file to your repository: `/dependencies/gemfile.lock` + +
+Click here to copy the file + +```gem +GEM + remote: https://rubygems.org/ + specs: + activesupport (6.1.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + ast (2.4.1) + concurrent-ruby (1.1.7) + i18n (1.8.7) + concurrent-ruby (~> 1.0) + jaro_winkler (1.5.4) + minitest (5.14.3) + parallel (1.20.1) + parser (3.0.0.0) + ast (~> 2.4.1) + rack (2.2.3) + rainbow (3.0.0) + rexml (3.2.4) + rubocop (0.82.0) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.7.0.1) + rainbow (>= 2.2.2, < 4.0) + rexml + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 2.0) + rubocop-github (0.16.0) + rubocop (<= 0.82.0) + rubocop-performance (~> 1.0) + rubocop-rails (~> 2.0) + rubocop-performance (1.7.1) + rubocop (>= 0.82.0) + rubocop-rails (2.6.0) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 0.82.0) + rubocop-rspec (1.41.0) + rubocop (>= 0.68.1) + ruby-progressbar (1.11.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + unicode-display_width (1.7.0) + zeitwerk (2.4.2) + +PLATFORMS + ruby + +DEPENDENCIES + rubocop (~> 0.82.0) + rubocop-github (~> 0.16.0) + rubocop-performance (~> 1.7.1) + rubocop-rails (~> 2.5) + rubocop-rspec (~> 1.41.0) + +BUNDLED WITH + 2.1.4 +``` + +
+ +- Commit the code +- Open Pull request diff --git a/docs/Exercises/04-Create-CT-Actions.md b/docs/Exercises/04-Create-CT-Actions.md new file mode 100644 index 0000000..d50b9ee --- /dev/null +++ b/docs/Exercises/04-Create-CT-Actions.md @@ -0,0 +1,89 @@ +# Creating basic CT Github Action + +This exercise will walk you through setting up *Continuous Testing* on your current repository. + +The objective of *Continuous Testing* is to achieve constant feedback on your changes to your code base and enable the process of testing your code base. + +**GitHub Actions** run off of workflow files that are managed and maintained in your repository. The action we are going to "install" on our repository uses an open source Action called the [Super Linter](https://github.com/github/super-linter). This action will review changes to the code and run a linter against it to ensure code sanity. + +## Add a GitHub Action workflow file + +1. Create a new branch of code called `CT` +1. Create a new file named `.github/workflows/ct.yml` +1. Copy the code below to the newly created file: + ```yaml + --- + ######## + ######## + ## CT ## + ######## + ######## + name: Continuous Testing + + # + # Documentation: + # https://help.github.com/en/articles/workflow-syntax-for-github-actions + # + + ############################# + # Start the job on all push # + ############################# + # Don't need to run on push to master/main + on: + push: + branches-ignore: + - 'master' + - 'main' + + ############### + # Set the Job # + ############### + jobs: + build: + # Name the Job + name: CT + # Set the agent to run on + runs-on: ubuntu-latest + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + ################################ + # Run Linter against code base # + ################################ + - name: Lint Code Base + uses: github/super-linter@v4 + env: + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: main + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ``` + +1. Commit the file. + +This workflow file is set up to run when a push is made to branches in the repository, unless they are pushed to the `main` or `master` branch. This is controlled by this section of the code: + +```yaml + push: + branches-ignore: + - 'master' + - 'main' +``` + +When we push a change to a branch, the GitHub Action will clone the repository code base, and run the Super Linter against the changes. + +## Running your GitHub Action + +1. Open a pull request with the `CT` branch into the `main` branch. + + In the pull request, you will see the GitHub Actions job running and its results. You can review the logs of the run and the steps it took by clicking on **Details** next to the GitHub Action. You can experiment with this Action, but making additional updates to the code and committing it. + +1. Merge the pull request. diff --git a/docs/Exercises/05-Create-Security-Scan.md b/docs/Exercises/05-Create-Security-Scan.md new file mode 100644 index 0000000..22d6628 --- /dev/null +++ b/docs/Exercises/05-Create-Security-Scan.md @@ -0,0 +1,71 @@ +# Creating GitHub Security Scan Actions + +The objective of *Security Scanning* is to achieve constant feedback on your codes security risks and enable the process of testing your code base. + +**GitHub Actions** run off of workflow files that are managed and maintained in your repository. + +## Add a GitHub Action workflow file + +1. Create a new branch of code called `Security` +1. Create a new file named `.github/workflows/security.yml` +1. Copy the code below to the newly created file: + ```yml + --- + ########################## + ########################## + ## CodeQL Security Scan ## + ########################## + ########################## + name: CodeQl Analysis + + # + # Documentation: + # https://help.github.com/en/articles/workflow-syntax-for-github-actions + # https://github.com/github/codeql-action + # + + ############################# + # Start the job on all push # + ############################# + on: + push: + branches-ignore: + - 'master' + - 'main' + + ############### + # Set the Job # + ############### + jobs: + scan: + # Name the Job + name: CodeQL Analysis + # Set the agent to run on + runs-on: ubuntu-latest + ################## + # Load all steps # + ################## + steps: + ########################## + # Checkout the code base # + ########################## + - name: Checkout Code + uses: actions/checkout@v2.3.4 + with: + # Full git history is needed to get a proper list of changed files + fetch-depth: 0 + + ##################### + # Initialize CodeQL # + ##################### + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: python + + ####################### + # Run CodeQL Analysis # + ####################### + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + ``` diff --git a/docs/Exercises/06-Upload-Download-Artifacts.md b/docs/Exercises/06-Upload-Download-Artifacts.md new file mode 100644 index 0000000..3221856 --- /dev/null +++ b/docs/Exercises/06-Upload-Download-Artifacts.md @@ -0,0 +1,30 @@ +# Uploading and Downloading build artifacts on Github Workflow + +- If your job produces a build artifact that users need to view, or need to be passed to another build machine, the **Github Actions** upload and download can help with this process. + +### Exercise: Add Upload and Download + +1. Add the following code to your build pipeline, and it will then start publishing the artifact once the step has completed. + +1. Create a new branch called `Artifacts` +1. Copy and paste the following code snippet into one of your working workflow files: + +```yml +# Upload an artifact to GitHub +- name: Upload Artifact to Github Build Job + uses: actions/upload-artifact@v2 + with: + name: my-artifact + path: path/to/artifact/world.txt + +# Download an artifact from GitHub +- name: Download Artifact from Github Build Job + uses: actions/download-artifact@v2 + with: + name: my-artifact +``` +> **Note:** Please update the path to an artifact that was created in the build process. + +### Linkage +- [Upload Artifact](https://github.com/actions/upload-artifact) +- [Download Artifact](https://github.com/actions/download-artifact) diff --git a/docs/Exercises/06.A-Upload-Download-Artifacts- from Artifactory.md b/docs/Exercises/06.A-Upload-Download-Artifacts- from Artifactory.md new file mode 100644 index 0000000..4c60e36 --- /dev/null +++ b/docs/Exercises/06.A-Upload-Download-Artifacts- from Artifactory.md @@ -0,0 +1,49 @@ +# Uploading and Downloading build artifacts on Github Workflow + +- If your job produces a build artifact that users need to view, or need to be passed to another build machine, the **Github Actions** upload and download can help with this process. +- This can be achieved with the [JFROG CLI Action](https://github.com/marketplace/actions/jfrog-cli) + +### Exercise: Add Upload and Download + +1. Add the following code to your build pipeline, and it will then start publishing the artifact once the step has completed. + +1. Create a new branch called `Artifacts` +1. Copy and paste the following code snippet into one of your working workflow files: +```yaml +# Upload an artifact to Artifactory +name: Upload to Artifactory + uses: Deepakanandrao/jfrog-cli@v3 + with: + cli_cmd: | # commands to be excuted + 'jfrog rt u "(*).tgz" my-local-repo/{1}/ --recursive=false' + env: + SERVER_URL: ${{ secrets.SERVER_URL }} # Required (e.g. https://jfrogy.com/artifactory) + SERVER_ID: ${{ secrets.SERVER_ID }} # Optional - Name to be recognized server with + DISTRIBUTION_URL: ${{ secrets.SERVER_URL }} # Optional + ACCESS_TYPE: ${{ secrets.ACTION_TYPE }} # Required (username-password, access-token, api-key) + USERNAME: ${{ secrets.USERNAME }} # Required any of one of the following + PASSWORD: ${{ secrets.PASSWORD }} + API_KEY: ${{ secrets.API_KEY }} + ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} + + # Download an artifact from Artifactory + name: Download from Artifactory + uses: Deepakanandrao/jfrog-cli@v3 + with: + cli_cmd: | # commands to be excuted + 'jfrog rt dl my-local-repo/cool-froggy.zip' + env: + SERVER_URL: ${{ secrets.SERVER_URL }} # Required (e.g. https://jfrogy.com/artifactory) + SERVER_ID: ${{ secrets.SERVER_ID }} # Optional - Name to be recognized server with + DISTRIBUTION_URL: ${{ secrets.SERVER_URL }} # Optional + ACCESS_TYPE: ${{ secrets.ACTION_TYPE }} # Required (username-password, access-token, api-key) + USERNAME: ${{ secrets.USERNAME }} # Required any of one of the following + PASSWORD: ${{ secrets.PASSWORD }} + API_KEY: ${{ secrets.API_KEY }} + ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} +``` +> **Note:** Please update the path to an artifact that was created in the build process. + +### Linkage +- [JFrog CLI Action](https://github.com/marketplace/actions/jfrog-cli) +- [Action Repo](https://github.com/Deepakanandrao/jfrog-cli) diff --git a/docs/Exercises/07-Create-CD-Actions.md b/docs/Exercises/07-Create-CD-Actions.md new file mode 100644 index 0000000..67aef09 --- /dev/null +++ b/docs/Exercises/07-Create-CD-Actions.md @@ -0,0 +1,8 @@ +# Continuous Delivery / Continuous Deployment + +Continuous delivery and/or continuous Deployment can greatly ease the issues of getting your finished code or product into your end users hands. +Automation of the process greatly helps reduce human issues and enables for faster delivery/deployment. + +It all boils down to what you are building, and how often it is built. If you only need to cut a release every few months, then automation may not be ideal, but a solid workflow could help ease the process. If you are deploying weekly, daily, hourly, then having the workflow connected to events will greatly help the process. + +The examples we have will help solve most of the use cases. diff --git a/docs/Exercises/07.A-Deploy-Prod.md b/docs/Exercises/07.A-Deploy-Prod.md new file mode 100644 index 0000000..a856570 --- /dev/null +++ b/docs/Exercises/07.A-Deploy-Prod.md @@ -0,0 +1,449 @@ +# Deploy on push to `master` or `main` + +In this session, we are going to be deploying the application to various production style environments. This will take the built **Docker** Container and deploy it to one or more of the various environments. + +### Exercise: Deploy Docker images + +> **Note:** Before you add the code below, you will need to setup **Github Secrets** To help hold credentials and hidden endpoints. + +- **DockerHub** + - `DOCKERHUB_USERNAME` - Username to authenticate to DockerHub + - `DOCKERHUB_PASSWORD` - Password to authenticate to DockerHub +- **Github Container Registry** + - `GCR_USERNAME` - Username to authenticate to GitHub + - `GCR_TOKEN` - GitHub Personal Access Token with access rights to container registry +- **AWS** + - `AWS_ACCESS_KEY_ID` - Access key id to authenticate to AWS + - `AWS_SECRET_ACCESS_KEY` - Secret Access key to authenticate to AWS + - `ECR_REGISTRY` - AWS ECR Registry to push container image + - `ECR_REPOSITORY` - AWS ECR repository to push container image +--- +#### Deploy to DockerHub + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-docker.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Production + +# Controls when the action will run. +on: + push: + branches: + - 'master' + - 'main' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + ###################### + # Login to DockerHub # + ###################### + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + DOCKER_ORG/demo-action:latest + DOCKER_ORG/demo-action:v1 + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- + +#### Deploy to GitHub Container Registry + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-gcr.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Production + +# Controls when the action will run. +on: + push: + branches: + - 'master' + - 'main' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + ###################################### + # Login to GitHub Container Registry # + ###################################### + - name: Login to GitHub Container registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ secrets.GCR_USERNAME }} + password: ${{ secrets.GCR_TOKEN }} + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ######################################## + # Convert repository name to lowercase # + ######################################## + - name: Repository Name to lowercase + run: | + echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ghcr.io/${{ env.IMAGE_REPOSITORY }}:latest + ghcr.io/${{ env.IMAGE_REPOSITORY }}:v1 + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- + +#### Deploy to AWS ECR + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-aws.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Production + +# Controls when the action will run. +on: + push: + branches: + - 'master' + - 'main' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + #################### + # Config AWS Creds # + #################### + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + ################# + # Login AWS ECR # + ################# + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:v1 + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- diff --git a/docs/Exercises/07.B-Deploy-Release.md b/docs/Exercises/07.B-Deploy-Release.md new file mode 100644 index 0000000..b81483d --- /dev/null +++ b/docs/Exercises/07.B-Deploy-Release.md @@ -0,0 +1,439 @@ +# Deploy Release + +In this session, we are going to be deploying the application to various production style environments. This will take the built **Docker** Container and deploy it to one or more of the various environments. This deployment is set to run only when a **GitHub Release** is created. + +### Exercise: Deploy Release images + +**Note:** Before you add the code below, you will need to setup **Github Secrets** To help hold credentials and hidden endpoints. + +- **DockerHub** + - `DOCKERHUB_USERNAME` - Username to authenticate to DockerHub + - `DOCKERHUB_PASSWORD` - Password to authenticate to DockerHub +- **Github Container Registry** + - `GCR_USERNAME` - Username to authenticate to GitHub + - `GCR_TOKEN` - GitHub Personal Access Token with access rights to container registry +- **AWS** + - `AWS_ACCESS_KEY_ID` - Access key id to authenticate to AWS + - `AWS_SECRET_ACCESS_KEY` - Secret Access key to authenticate to AWS + - `ECR_REGISTRY` - AWS ECR Registry to push container image + - `ECR_REPOSITORY` - AWS ECR repository to push container image +--- +#### Deploy Release to DockerHub + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-docker.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Publish Release + +# Controls when the action will run. +on: + release: + # Want to run the automation when a release is created + types: ['created'] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + ###################### + # Login to DockerHub # + ###################### + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + DOCKER_ORG/demo-action:latest + DOCKER_ORG/demo-action:${{ github.event.release.tag_name }} + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- + +#### Deploy Release to Github Container Registry + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-gcr.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Publish Release + +# Controls when the action will run. +on: + release: + # Want to run the automation when a release is created + types: ['created'] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + ###################################### + # Login to GitHub Container Registry # + ###################################### + - name: Login to GitHub Container registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ secrets.GCR_USERNAME }} + password: ${{ secrets.GCR_TOKEN }} + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ghcr.io/${{github.repository_owner}}/${{github.repository.name}}:latest + ghcr.io/${{github.repository_owner}}/${{github.repository.name}}:${{ github.event.release.tag_name }} + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- + +#### Deploy Release to AWS ECR + +1. Create a new branch called `Deploy` +1. Add the following file to your repository: `.github/workflows/deploy-prod-aws.yml` + +
+Click here to add the file + +```yaml +# This is a basic workflow to help you get started with Actions + +name: Docker Publish Release + +# Controls when the action will run. +on: + release: + # Want to run the automation when a release is created + types: ['created'] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + docker-prod-release: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # You could use the following lines to help make sure only X people start the workflow + # if: github.actor == 'admiralawkbar' || github.actor == 'jwiebalk' + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout source code + uses: actions/checkout@v2 + + ######################### + # Install Docker BuildX # + ######################### + - name: Install Docker BuildX + uses: docker/setup-buildx-action@v1 + + #################### + # Config AWS Creds # + #################### + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + ################# + # Login AWS ECR # + ################# + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # Create a GitHub Issue with the info from this build + - name: Create GitHub Issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Deploying to production", + body: 'Currently deploying...' + }) + console.log('create', create) + return create.data.number + + ########################################### + # Build and Push containers to registries # + ########################################### + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: true + tags: | + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ github.event.release.tag_name }} + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.repository_owner}}/packages?repo_name=${{github.repository.name}} + + - name: Update issue success + uses: actions/github-script@v3.1.0 + if: success() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Successful!y deployed production" + }) + + - name: Update issue failure + uses: actions/github-script@v3.1.0 + if: failure() + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: "Failed to deploy to production" + }) +``` + +
+ +- Commit the code +- Open Pull request + +--- diff --git a/docs/Exercises/08.A-GitHub-Script-Actions.md b/docs/Exercises/08.A-GitHub-Script-Actions.md new file mode 100644 index 0000000..76f5fcf --- /dev/null +++ b/docs/Exercises/08.A-GitHub-Script-Actions.md @@ -0,0 +1,81 @@ +# GitHub Script Actions + +The [GitHub Script Action](https://github.com/marketplace/actions/github-script) is a very powerful **Github Action** that can be used in your workflows. + +It uses [Octokit](https://github.com/octokit/rest.js/) to help make calling GitHub API's easy and repeatable. +With this information, you can then create issues, create releases, update endpoints, etc. Below is a simple example of creating and updating an issue using the tooling. + + +### Exercise: Add GitHub Scripts + +1. Create a new branch called `Scripts` +1. Create a new file named `.github/workflows/create-issue.yml` +1. Copy the code below to the newly created file: + + ```yaml + # This is a basic workflow to help you get started with Actions + + name: Create Issue + + # Controls when the action will run. + on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + + # A workflow run is made up of one or more jobs that can run sequentially or in parallel + jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + # Runs a single command using the runners shell + - name: Run a one-line script + run: echo Hello, world! + + - name: Create issue + uses: actions/github-script@v3.1.0 + id: create-issue + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const create = await github.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "New issue created", + body: 'Heres some base data' + }) + console.log('create', create) + return create.data.number + + - name: Update issue + uses: actions/github-script@v3.1.0 + with: + # https://octokit.github.io/rest.js/v18#issues-create + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: "${{ steps.create-issue.outputs.result }}", + title: "New issue created", + body: 'Adding a comment!' + }) + ``` + +1. Commit the file. +1. Open a pull request with the `Scripts` branch into the `main` branch. +1. Merge the pull request. + +### Linage +- [GitHub Script Action](https://github.com/marketplace/actions/github-script) +- [Octokit Create Issue doc](https://octokit.github.io/rest.js/v18#issues-create) \ No newline at end of file diff --git a/docs/Exercises/08.B-Add-Deployment-API.md b/docs/Exercises/08.B-Add-Deployment-API.md new file mode 100644 index 0000000..b52a6ca --- /dev/null +++ b/docs/Exercises/08.B-Add-Deployment-API.md @@ -0,0 +1,42 @@ +# Utilizing GitHub Deployment API +This exercise will walk you through utilizing the **Github Deployment API** on your current repository. + +The objective of the Deployment API is to help showcase and link your environments to the events that created them. + +## Update your GitHub Action workflow file + +1. Create a new branch of code called `API` +1. Edit one of your `deploy-docker.yml` workflow files +1. Copy the code before and after the deployment: + + ```yml + # Update deployment API + - name: start deployment + uses: bobheadxi/deployments@v0.4.3 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Production + + # ... Code that deploys the docker image to an environment here... + + # Update Deployment API + - name: update deployment status + uses: bobheadxi/deployments@v0.4.3 + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + env_url: https://github.com/orgs/${{github.owner}}/packages?repo_name=${{github.repository}} + ``` + +1. Commit the file. +1. Open a pull request with the `API` branch into the `main` branch. +1. Merge the pull request. +1. You will now see the job run and deploy your Docker image, and update the deployment info in your repository. + +### Linkage +- [GitHub Deployment Action](https://github.com/marketplace/actions/github-deployments) \ No newline at end of file diff --git a/docs/Exercises/08.C-Add-Wait-For-Steps.md b/docs/Exercises/08.C-Add-Wait-For-Steps.md new file mode 100644 index 0000000..81d5211 --- /dev/null +++ b/docs/Exercises/08.C-Add-Wait-For-Steps.md @@ -0,0 +1,24 @@ +# Wait for step to complete Action +You can use the following code snippet to add wait for completion of steps. +This will allow you to make decisions on where another step from another job has completed, and what you want to do from that event. + +```yaml +- name: Wait for app build success + uses: fountainhead/action-wait-for-check@v1.0.0 + id: wait-for-build-success + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: CI + ref: ${{ github.event.pull_request.head.sha || github.sha }} + +- name: Perform Some Step + if: steps.wait-for-build-success.outputs.conclusion == 'success' + run: echo "We have success" + +- name: Error message on failure + if: steps.wait-for-build-success.outputs.conclusion == 'failure' + run: echo "ERROR! Build failure! +``` + +### Linkage +- [Wait for check](]https://github.com/fountainhead/action-wait-for-check) \ No newline at end of file diff --git a/docs/Exercises/08.D-Split-Jobs-for-Speed.md b/docs/Exercises/08.D-Split-Jobs-for-Speed.md new file mode 100644 index 0000000..32c95f6 --- /dev/null +++ b/docs/Exercises/08.D-Split-Jobs-for-Speed.md @@ -0,0 +1,6 @@ +# Splitting up jobs + + As you can see, some steps take much time, and others are fairly quick. + As you progress though your knowledge of **GitHub Actions**, you should be able to split up jobs and steps, and set up advanced wait conditions to help speed up your pipelines. + + By doing so, you make sure you get reliable, and instant feedback from your build process. \ No newline at end of file diff --git a/docs/Exercises/09-Create-New-Repo-To-Pull-In-Container.md b/docs/Exercises/09-Create-New-Repo-To-Pull-In-Container.md new file mode 100644 index 0000000..ea54cee --- /dev/null +++ b/docs/Exercises/09-Create-New-Repo-To-Pull-In-Container.md @@ -0,0 +1,18 @@ +- Create a new repo and make this repo an action and pull in the container and use it! + +- You could create an `action.yml` on the root of repo with the following data + +```yml +name: 'My Action' +author: 'GitHub' +description: 'It is a simple GitHub Action' +runs: + using: 'docker' + image: 'docker://ghcr.io/ORG_NAME/REPO_NAME@VERSION' + # image: 'Dockerfile` # Will run the dockerfile from the root of the repo and not pull it like from above +branding: + icon: 'check-square' + color: 'white' +``` + +- You can then open a new repo, create a worklfow, and point to this repo, and it will luanch the docker contrainer \ No newline at end of file diff --git a/docs/Exercises/README.md b/docs/Exercises/README.md new file mode 100644 index 0000000..9a63d54 --- /dev/null +++ b/docs/Exercises/README.md @@ -0,0 +1,52 @@ +# :pencil2: Exercises + +The goal of these exercises is to create a CI/CT/CD workflow with GitHub Actions. + +As you work progressively along all the ordered files, your workflow will become more complex and thorough. + +### Steps 1: Create Continuous Integration (CI) + +- [Create Dockerfile](./01-Create-Dockerfile.md) +- [Create CI Action](./02-Create-CI-Action.md) + +### Steps 2: Adding more complexity to the CI + +- These steps would be more informative if you adopt a Git Flow: + - [Create QA Branch](./02.A-Create-QA-Branch.md) + - [Create Context Job](./02.B-Create-Context-Job.md) + +### Steps 3: Dependency Management + +- [Create Dependabot Config](./03-Create-Dependabot-Config.md) +- [Lock Your Dependencies](./03.A-Lock-Dependencies.md) + +### Step 4: Add Continuous Testing (CT) + +- [Create CT Actions](./04-Create-CT-Actions.md) + +### Step 5: Security Scans + +- [Create Security Scan](./05-Create-Security-Scan.md) + +### Step 6: Actions for Artifacts Management + +- [Upload and Download Build Artifacts](./06-Upload-Download-Artifacts.md) + +### Step 7: Create Continuous Deployment (CD) + +- [Create CD Actions](./07-Create-CD-Actions.md) +- [Deploy Docker Image](./07.A-Deploy-Prod.md) +- [Deploy Release Images](./07.B-Deploy-Release.md) + +### Optional: Using Actions beyond CI/CT/CD + +- [Using Actions to Create Issues](./08.A-GitHub-Script-Actions.md) +- [Using GitHub's API for Deployment to Update Environments](./08.B-Add-Deployment-API.md) +- [**Advanced**: Wait for Steps to Require Other Jobs to Complete](./08.C-Add-Wait-For-Steps.md) +- [**Advanced**: Additional information on Best Practices for Complex Workflows](./08.D-Split-Jobs-for-Speed.md) +- [**Advanced**: Reusing a Local Action](./09-Create-New-Repo-To-Pull-In-Container.md) + +## :book: Additional Resources + +- [GitHub Actions Documentation](https://docs.github.com/en/free-pro-team@latest/actions) +- [Self-paced Learning Lab Course on DevOps Pipeline with GitHub Actions](https://lab.github.com/githubtraining/devops-with-github-actions) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..fc3f7a1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,14 @@ +# Welcome to GitHub Actions + +![welcome-actions](https://user-images.githubusercontent.com/6351798/82074464-074e7880-9698-11ea-84e2-200e49485f5c.png) + + +Today is a very exciting day as it marks the beginning of your adventure with GitHub Actions! + +As we move through these materials, please keep the following in mind: this class is for you! Be sure to follow along, participate in the activities, and ask lots of questions! + +This content is used for the GitHub Actions and Migrations trainings with GitHub Professional Services. To learn more, visit https://services.github.com/. + +--- + +πŸ‘ˆ Click **Getting Started** to begin! diff --git a/docs/_coverpage.md b/docs/_coverpage.md new file mode 100644 index 0000000..a427812 --- /dev/null +++ b/docs/_coverpage.md @@ -0,0 +1,5 @@ +![logo](images/cover.png ":no-zoom") + +# The Official GitHub Actions Training Manual + +Scroll down to begin diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..e53b136 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,62 @@ +- [**Getting Started**](00.0_getting-started.md) +- [**Introduction to Github Actions**](01.0_actions-intro.md) + - [**About Actions**](01.1_actions-about.md) + - [**Pricing and Usage Limits**](01.2_actions-pricing.md) + - [**Starter Workflows**](01.3_actions-starter-workflows.md) + - [**Our Learning Path**](01.4_actions-hello.md) + - [**Your First Action**](01.5_exercise-2.md) + - [**Exercise 2 - A Basic CI Action**](01.5_exercise-2.md?id=exercise-2-a-basic-ci-action) + - [**Exercise 2 A - Protected Branches**](01.5_exercise-2.md?id=exercise-2-a-protected-branches) + - [**Exercise 2 B - Actions Context**](01.5_exercise-2.md?id=exercise-2-b-actions-context) + - [**Exercise 2 C - Manual Jobs**](01.5_exercise-2.md?id=exercise-2-c-manual-jobs) + - [**Section Wrap Up**](01.6_workflow-intro.md) +- [**Creating Workflows**](02.1_actions-ecosystem.md) + - [**Events**](02.2_events.md) + - [**Workflows**](02.3_workflows.md) + - [**Jobs**](02.4_jobs.md) + - [**Steps**](02.5_steps.md) + - [**Real Time Logs**](02.6_reporting.md) + - [**Updating Dependencies**](02.7_exercise_3.md) + - [**Exercise 3 - Dependabot**](02.7_exercise_3.md?id=exercise-3-dependabot) + - [**Exercise 3 A - Dependency Locking**](02.7_exercise_3.md?id=exercise-3-a-dependency-locking) + - [**How GitHub Uses Actions**](02.8_actions-hackathon-case-study.md) + - [**Caching Within Actions**](02.9_caching.md) + - [**Section Wrap Up**](02.10_secrets.md) + - [**Section Wrap Up**](02.11_continuous-integration.md) +- [**Continuous Integration**](03.1_ci-overview.md) + - [**CI using GitHub Actions**](03.2_ci-with-actions.md) + + + - [**Continuous Testing With Actions**](03.5_ct-action.md) + - [**Security Scanning**](03.6_security-scan.md) + - [**Using Artifacts In Actions**](03.7_using-artifacts.md) + - [**Exercise 6 - Uploading and Downloading Artifacts**](03.7_using-artifacts?id=exercise-6-uploading-and-downloading-artifacts-in-actions) + - [**Exercise 6 A - Uploading and Downloading Artifacts with Artifactory**](03.7_using-artifacts?id=exercise-6-a-uploading-and-downloading-artifacts-with-artifactory-in-actions) + - [**Section Wrap Up**](03.8_continuous-delivery.md) +- [**Continuous Delivery/Deployment**](04.1_cd-overview.md) + + + - [**Creating A Continuous Delivery Action**](04.5_cd-action.md) + - [**Exercise 7 - Create CD Actions**](04.5_cd-action?id=exercise-7-create-cd-actions) + - [**Exercise 7 A - Deploy on Push**](04.5_cd-action?id=exercise-7-a-deploy-on-push-to-master-or-main) + - [**Exercise 7 B - Deploy Release**](04.5_cd-action?id=exercise-7-b-deploy-a-release) + - [**Using GitHub Script**](04.6_exercise-8.md) + - [**Exercise 8 A - GitHub Script**](04.6_exercise-8?id=exercise-8-a-github-script) + - [**Exercise 8 B - Deployment API**](04.6_exercise-8?id=exercise-8-b-deployment-api) + - [**Exercise 8 C - Wait For Step**](04.6_exercise-8?id=exercise-8-c-wait-for-step) + - [**Exercise 8 D - Splitting Jobs**](04.6_exercise-8?id=exercise-8-d-splitting-jobs) + - [**Section Wrap Up**](04.7_on-to-actions.md) +- [**Action Overview**](05.1_action-overview.md) + - [**Action Types**](05.2_action-type.md) + - [**Action Metadata**](05.4_action-metadata.md) + - [Inputs](05.4.1_inputs.md) + - [Outputs](05.4.2_outputs.md) + - [Entrypoint](05.4.3_entrypoint.md) + - [**More on Virtual Environments**](05.5_action-runner-env.md) + - [**Opting for Self-Hosted Runners**](05.5b_self-hosted-runners.md) + - [**Tools to Help Write Actions**](05.6_custom-action.md) + - [**Writing Custom Actions**](05.7_exercise-9.md) +- [**Summary**](06.0_summary.md) + + diff --git a/docs/docker-workflows.md b/docs/docker-workflows.md new file mode 100644 index 0000000..ff079de --- /dev/null +++ b/docs/docker-workflows.md @@ -0,0 +1,39 @@ +## Workflows for Docker {docsify-ignore-all} + +Let's take a quick look πŸ‘€ at publishing a Docker image to the Docker Hub as well as GitHub Container registry. + +### Publish an image + +```yaml +name: Publish Docker image + +on: + release: + types: [published] + +jobs: + push_to_registries: + name: Push Docker image to multiple registries + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Push to Docker Hub + uses: docker/build-push-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + repository: my-docker-hub-namespace/my-docker-hub-repository + tag_with_ref: true + + - name: Push to GitHub Packages + uses: docker/build-push-action@v1 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: containers.pkg.github.com + repository: my-org/my-repo/my-image + tag_with_ref: true +``` diff --git a/docs/e-missing-link.md b/docs/e-missing-link.md new file mode 100644 index 0000000..94cd853 --- /dev/null +++ b/docs/e-missing-link.md @@ -0,0 +1 @@ +## There has been no link provided for this resource. Please contact project contributors to initiate a fix diff --git a/docs/images/Actions.png b/docs/images/Actions.png new file mode 100644 index 0000000..75366fd Binary files /dev/null and b/docs/images/Actions.png differ diff --git a/docs/images/Continous-integration.png b/docs/images/Continous-integration.png new file mode 100644 index 0000000..a6358c8 Binary files /dev/null and b/docs/images/Continous-integration.png differ diff --git a/docs/images/Developers.png b/docs/images/Developers.png new file mode 100644 index 0000000..a22e139 Binary files /dev/null and b/docs/images/Developers.png differ diff --git a/docs/images/action-hackathon.png b/docs/images/action-hackathon.png new file mode 100644 index 0000000..de9ba69 Binary files /dev/null and b/docs/images/action-hackathon.png differ diff --git a/docs/images/action-metadata.png b/docs/images/action-metadata.png new file mode 100644 index 0000000..dfa0af8 Binary files /dev/null and b/docs/images/action-metadata.png differ diff --git a/docs/images/actions-ci.png b/docs/images/actions-ci.png new file mode 100644 index 0000000..dda2628 Binary files /dev/null and b/docs/images/actions-ci.png differ diff --git a/docs/images/actions-marketplace.png b/docs/images/actions-marketplace.png new file mode 100644 index 0000000..07636fc Binary files /dev/null and b/docs/images/actions-marketplace.png differ diff --git a/docs/images/actions-overview.png b/docs/images/actions-overview.png new file mode 100644 index 0000000..60064f4 Binary files /dev/null and b/docs/images/actions-overview.png differ diff --git a/docs/images/actions-tab.png b/docs/images/actions-tab.png new file mode 100644 index 0000000..9e88da3 Binary files /dev/null and b/docs/images/actions-tab.png differ diff --git a/docs/images/automate-your-workflow.png b/docs/images/automate-your-workflow.png new file mode 100644 index 0000000..3667396 Binary files /dev/null and b/docs/images/automate-your-workflow.png differ diff --git a/docs/images/community-actions.png b/docs/images/community-actions.png new file mode 100644 index 0000000..5564c63 Binary files /dev/null and b/docs/images/community-actions.png differ diff --git a/docs/images/cover.png b/docs/images/cover.png new file mode 100644 index 0000000..ea6ff54 Binary files /dev/null and b/docs/images/cover.png differ diff --git a/docs/images/custom-action.png b/docs/images/custom-action.png new file mode 100644 index 0000000..12812d5 Binary files /dev/null and b/docs/images/custom-action.png differ diff --git a/docs/images/devops-workflow.png b/docs/images/devops-workflow.png new file mode 100644 index 0000000..847a941 Binary files /dev/null and b/docs/images/devops-workflow.png differ diff --git a/docs/images/ecosystem.png b/docs/images/ecosystem.png new file mode 100644 index 0000000..df57ba0 Binary files /dev/null and b/docs/images/ecosystem.png differ diff --git a/docs/images/enabled-workflows.png b/docs/images/enabled-workflows.png new file mode 100644 index 0000000..29cc41a Binary files /dev/null and b/docs/images/enabled-workflows.png differ diff --git a/docs/images/events-trigger-workflows.png b/docs/images/events-trigger-workflows.png new file mode 100644 index 0000000..c40d5c9 Binary files /dev/null and b/docs/images/events-trigger-workflows.png differ diff --git a/docs/images/gh-actions-runner-lc.png b/docs/images/gh-actions-runner-lc.png new file mode 100644 index 0000000..25460c8 Binary files /dev/null and b/docs/images/gh-actions-runner-lc.png differ diff --git a/docs/images/jobs-overview.png b/docs/images/jobs-overview.png new file mode 100644 index 0000000..9d7cd84 Binary files /dev/null and b/docs/images/jobs-overview.png differ diff --git a/docs/images/learning-lab.png b/docs/images/learning-lab.png new file mode 100644 index 0000000..f24f42e Binary files /dev/null and b/docs/images/learning-lab.png differ diff --git a/docs/images/metadata-options.png b/docs/images/metadata-options.png new file mode 100644 index 0000000..d10f41a Binary files /dev/null and b/docs/images/metadata-options.png differ diff --git a/docs/images/punchcode.png b/docs/images/punchcode.png new file mode 100644 index 0000000..310ee5a Binary files /dev/null and b/docs/images/punchcode.png differ diff --git a/docs/images/recent-run-status.png b/docs/images/recent-run-status.png new file mode 100644 index 0000000..2cd34cb Binary files /dev/null and b/docs/images/recent-run-status.png differ diff --git a/docs/images/reviewers.png b/docs/images/reviewers.png new file mode 100644 index 0000000..10b649c Binary files /dev/null and b/docs/images/reviewers.png differ diff --git a/docs/images/step-logs.png b/docs/images/step-logs.png new file mode 100644 index 0000000..701c96c Binary files /dev/null and b/docs/images/step-logs.png differ diff --git a/docs/images/steps-overview.png b/docs/images/steps-overview.png new file mode 100644 index 0000000..422bcfa Binary files /dev/null and b/docs/images/steps-overview.png differ diff --git a/docs/images/workflow-file-overview.png b/docs/images/workflow-file-overview.png new file mode 100644 index 0000000..92a10be Binary files /dev/null and b/docs/images/workflow-file-overview.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..79d6f92 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,77 @@ + + + + + GitHub Actions Training Manual + + + + + + + + + + + + + +
+ + + + + + + + + + + + + diff --git a/docs/java-workflows.md b/docs/java-workflows.md new file mode 100644 index 0000000..11cab98 --- /dev/null +++ b/docs/java-workflows.md @@ -0,0 +1,81 @@ +## Workflows for java {docsify-ignore-all} + +Let's take a quick look πŸ‘€ at a few workflow examples. These examples explore how to do some basic CI/CD with Java packages using Maven. Maven is **not** the only option when it comes to Java, but the focus here is on workflow syntax and not necessarily the exact tooling in place. + +### Maven workflow examples + +**Build, test and stage a Java package** + +```yaml +name: Java CI + +on: [push] + +jobs: + build-package: + runs-on: ubuntu-latest + + steps: + - name: Checkout code into runner environment + uses: actions/checkout@v2 + + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + architecture: x64 + + - name: Build using Maven + run: mvn -B package --file pom.xml + + - name: Creating staging directories on runner + run: mkdir staging && cp target/*.jar staging + + - name: Stage artifact for delivery + uses: actions/upload-artifact@v1 + with: + name: my-package-name + path: staging +``` + +**Publish a Java package** + +```yaml +name: Publish package to the Maven Central Repository and GitHub Packages + +on: + release: + types: [created] + +jobs: + publish-packages: + runs-on: ubuntu-latest + + steps: + - name: Checkout code into the runner environment + uses: actions/checkout@v2 + + - name: Set up Java for publishing to Maven Central Repository + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + + - name: Publish to the Maven Central Repository + run: mvn -B deploy + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + + - name: Set up Java for publishing to GitHub Packages + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Publish to GitHub Packages + run: mvn -B deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` diff --git a/docs/js-workflows.md b/docs/js-workflows.md new file mode 100644 index 0000000..f18dcd6 --- /dev/null +++ b/docs/js-workflows.md @@ -0,0 +1,82 @@ +## Workflows for js/ts {docsify-ignore-all} + +Let's take a quick look πŸ‘€ at a few workflow examples. These examples explore how to do some basic CI/CD with JavaScript using Node.js. NPM is **not** the only option when it comes to JavaScript, but the focus here is on workflow syntax and not necessarily the exact tooling in place. + +### Node.js CI + +```yaml +name: Node.js CI + +on: [push] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x, 10.x, 12.x] + + steps: + - name: Checkout repo code into runner environment + uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Build code with npm + run: npm run build --if-present + + - name: Test code with npm + run: npm test + env: + CI: true +``` + +### Publish packages to NPM and GitHub packages + +```yaml +name: Node.js Package + +on: + release: + types: [created] + +jobs: + publish-packages: + runs-on: ubuntu-latest + + steps: + - name: Checkout code from repo to runner + uses: actions/checkout@v2 + + - name: Setup .npmrc file to publish to npm + uses: actions/setup-node@v1 + with: + node-version: "10.x" + registry-url: "https://registry.npmjs.org" + + - name: Install deps + run: npm install + + - name: Publish to npm + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Setup .npmrc file to publish to GitHub Packages + uses: actions/setup-node@v1 + with: + registry-url: "https://npm.pkg.github.com" + scope: "@octocat" # Defaults to the user or organization that owns the workflow file + + - name: Publish to GitHub Packages + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` diff --git a/docs/python-workflows.md b/docs/python-workflows.md new file mode 100644 index 0000000..e275ced --- /dev/null +++ b/docs/python-workflows.md @@ -0,0 +1,78 @@ +## workflows for Python {docsify-ignore-all} + +Let's take a quick look πŸ‘€ at a few workflow examples. These examples explore how to do some basic CI/CD with Python. + +### Testing with pytest + +```yaml +name: Test Python package + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + + steps: + - name: Checkout repo into runner env + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Lint with flake8 + run: | + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: Test with pytest + run: | + pytest +``` + +### Publishing packages to registries + +```yaml +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo into runner env + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* +``` diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 0000000..c28853f --- /dev/null +++ b/docs/style.css @@ -0,0 +1,42 @@ +:root { + /* Make all topics in sidebar visible */ + --sidebar-width: 21rem; +} + +.table-wrapper { + box-shadow: 0 0 20px #20272c; +} + +.custom-info-box { + background-color: #dbedff; + padding: 10px; + border: 2px solid #79b8ff; + color: black; +} + +.custom-warn-box { + background-color: #fffdef; + padding: 10px; + border: 2px solid #fff5b1; + color: black; +} + +.custom-danger-box { + background-color: #ffeef0; + padding: 10px; + border: 2px solid #fdaeb7; + color: black; +} + +.custom-header { + cursor: default; + text-decoration: none !important; +} + +h1 > a, +h2 > a, +h3 > a, +h4 > a { + cursor: default; + text-decoration: none !important; +} diff --git a/docs/tab-style.css b/docs/tab-style.css new file mode 100644 index 0000000..5c40992 --- /dev/null +++ b/docs/tab-style.css @@ -0,0 +1,3 @@ +:root { + --docsifytabs-tab-highlight-color: #dbedff; +} diff --git a/library/entrypoint.sh b/library/entrypoint.sh new file mode 100644 index 0000000..048f20f --- /dev/null +++ b/library/entrypoint.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +################################################################################ +# Simple docker script +################################################################################ + +######## +# VARS # +######## +GITHUB_EVENT_PATH="${GITHUB_EVENT_PATH}" # Github Event Path +GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" # GitHub Org/Repo passed from system +GITHUB_RUN_ID="${GITHUB_RUN_ID}" # GitHub RUn ID to point to logs +GITHUB_SHA="${GITHUB_SHA}" # GitHub sha from the commit +GITHUB_TOKEN="${GITHUB_TOKEN}" # GitHub Token passed from environment +GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" # Github Workspace +VAR="${VAR:-nothing}" # Default var + +################################################################################ + +################## +# Run the script # +################## +echo "----------------------------------------" +echo "Welcome to this container action!" +echo "----------------------------------------" +echo "" + +echo "----------------------------------------" +echo "Heres whats in the env..." +printenv +echo "----------------------------------------" + +echo "You passed the Var:[${VAR}]" \ No newline at end of file diff --git a/library/python.py b/library/python.py new file mode 100644 index 0000000..d41cef2 --- /dev/null +++ b/library/python.py @@ -0,0 +1,199 @@ +import json +import sys +from os import getenv, path +from pprint import pprint + +import click # pylint: disable=import-error +import requests # pylint: disable=import-error +from dotenv import load_dotenv # pylint: disable=import-error + +env = load_dotenv() +api_url = getenv("API_URL", default="https://api.github.com/graphql") +github_token = getenv("GITHUB_TOKEN", default=None) + +if github_token is None: + sys.exit( + "GitHub Token is not set." + + "Please set the GITHUB_TOKEN env variable in your system or " + + "the .env file of your project." + ) + +client_id = getenv("CLIENT_ID", default="copy_labels.py") +headers = { + "Authorization": "bearer {github_token}".format(github_token=github_token), + "Accept": "application/vnd.github.bane-preview+json", + "Content-Type": "application/json", +} + + +def make_request(query, query_variables): + payload = {"query": query, "variables": query_variables} + response = requests.post(api_url, data=json.dumps(payload), headers=headers) + return response + + +def create_label(repo_id, label): + """ + Create label in the supplied repo. + + :param repo_id: Unique ID that represents the repo in GitHub + :type repo_id: str + :param label: Object with label information. + :type label: dict + :return: GitHub API request response + """ + + query_variables = { + "createLabelInput": { + "color": label["color"], + "description": label["description"], + "name": label["name"], + "repositoryId": repo_id, + } + } + + with open( + path.join(path.dirname(__file__), "queries/create_label.gql"), "r" + ) as query_file: + query = "".join(query_file.readlines()) + + response = make_request(query, query_variables).json() + print("Created label {label}".format(label=label["name"])) + + return response + + +def get_labels(owner, repo): + """ + Gets a list of labels from the supplied repo. + :param owner: Repo owner GitHub login. + :type owner: str + :param repo: Repository name. + :type repo: str + :return: A tuple with the GitHub id for the repository and a list of labels defined in the repository + """ + + query_variables = { + "owner": owner, + "name": repo, + } + + with open( + path.join(path.dirname(__file__), "queries/get_repo_data.gql"), "r" + ) as query_file: + query = "".join(query_file.readlines()) + + response = make_request(query, query_variables) + + status_code = response.status_code + result = response.json() + + if status_code >= 200 and status_code <= 300: + repo_id = result["data"]["repository"]["id"] + labels = result["data"]["repository"]["labels"]["nodes"] + + return repo_id, labels + else: + raise Exception( + "[ERROR] getting issue labels. Status Code: {status_code} - Message: {result}".format( + status_code=status_code, result=result["message"] + ) + ) + + +def delete_label(label_id): + """ + Delete the specified label + :param label_id: Label's node id. + :type label_id: str + :return: GitHub API request response. + """ + + query_variables = { + "deleteLabelInput": {"clientMutationId": client_id, "id": label_id} + } + + with open( + path.join(path.dirname(__file__), "queries/delete_label.gql"), "r" + ) as query_file: + query = "".join(query_file.readlines()) + + payload = {"query": query, "variables": query_variables} + result = requests.post(api_url, data=json.dumps(payload), headers=headers).json() + + return result + + +@click.command() +@click.option("--dry", is_flag=True) +@click.argument("source_repo") +@click.argument("target_repo") +def copy_labels(source_repo, target_repo, dry): + """ + Copy labels from the source repository to the target repository. + \f + :param source: The full name of a GitHub repo from where the labels will be copied from. Eg. github/opensourcefriday + :type source: str + :param target: The full name of a GitHub repo to where the labels will be copied. Eg. github/opensourcefriday + :type target: str + :return: + """ + source_owner, source_repo_name = source_repo.split("/") + target_owner, target_repo_name = target_repo.split("/") + + try: + print( + "Fetching labels for {source_repo_name} repo.".format( + source_repo_name=source_repo_name + ) + ) + _, source_repo_labels = get_labels(source_owner, source_repo_name) + print( + "Fetched labels for {source_repo_name}".format( + source_repo_name=source_repo_name + ) + ) + + print( + "Fetching labels for {target_repo_name} repo.".format( + target_repo_name=target_repo_name + ) + ) + target_repo_id, target_repo_labels = get_labels(target_owner, target_repo_name) + print( + "Fetched labels for {target_repo_name}".format( + target_repo_name=target_repo_name + ) + ) + + filtered_labels = list( + filter(lambda x: x not in target_repo_labels, source_repo_labels) + ) + + if dry: + print("This is just a dry run. No labels will be copied/created.") + print( + "{label_count} labels would have been created.".format( + label_count=len(filtered_labels) + ) + ) + pprint(filtered_labels, indent=4) + else: + print( + "Preparing to created {label_count} labels in {target_repo}".format( + label_count=len(filtered_labels), target_repo=target_repo + ) + ) + + for label in filtered_labels: + create_label(target_repo_id, label) + except Exception as error: + sys.exit(error) + + print("Done") + + +if __name__ == "__main__": + # Pylint doesn't know that @click.command takes care of injecting the + # function parameters. Disabling Pylint error. + copy_labels() # pylint: disable=no-value-for-parameter diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..ce700fd --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,10 @@ +# Train the Trainer Scripts +This directory contains scripts used in the class by the trainer + +## Main.js +This script will take a repository as a template and create a copy in the target organization for each user in the input file. +Input is a JSON array of github user names. +Sample usage: +``` +echo '["selkins13","chocrates"]' | node main.js --token --org --template --file /dev/stdinv +``` diff --git a/scripts/main.js b/scripts/main.js new file mode 100644 index 0000000..42b78d9 --- /dev/null +++ b/scripts/main.js @@ -0,0 +1,145 @@ +const { throttling } = require("@octokit/plugin-throttling"); +const { retry } = require("@octokit/plugin-retry"); +const { Octokit } = require("@octokit/rest"); +const git = require("@npmcli/git"); +const fs = require("fs"); +const MyOctokit = Octokit.plugin(throttling).plugin(retry); + +const sleep = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +let main = async () => { + const argv = require("yargs") + .option("token", { + alias: "t", + description: "personal access token with which to authenticate", + global: true, + demandOption: true, + }) + .option("org", { + alias: "o", + description: "Org to add the new repos", + global: true, + demandOption: true, + }) + .option("template", { + alias: "p", + description: + "Template repository that we will create for each user", + demandOption: true, + global: true, + }) + .option("file", { + alias: "f", + description: "json file with users", + global: true, + demandOption: true, + }) + .option("verbose", { + alias: "v", + description: "Print logs for debugging", + global: true, + }).argv; + + const client = new MyOctokit({ + auth: `token ${argv.token}`, + throttle: { + onRateLimit: (retryAfter, options) => { + console.warn( + `Request quota exhausted for request ${options.method} ${options.url}` + ); + console.warn( + `Retrying after ${retryAfter} seconds! Retry Count: ${options.request.retryCount}` + ); + return true; + }, + onAbuseLimit: (retryAfter, options) => { + console.warn( + `Abuse detected for request ${options.method} ${options.url}` + ); + return true; + }, + }, + }); + + const log = (action, result) => { + if (argv.verbose) { + console.log(`${action}: ${result}`); + } + }; + + const users = JSON.parse( + fs.readFileSync(argv.file, { encoding: "utf8", flag: "r" }) + ); + // Get each user + for (let user of users) { + const repoName = `${argv.template.split("/")[1]}-${user}`; + try { + // Bare Clone of "template" + let result = await git.spawn([ + "clone", + "--bare", + `https://${argv.token}@github.com/${argv.template}.git`, + ]); + log("Cloning template", JSON.stringify(result)); + + // Create repo in org + result = await client.repos.createInOrg({ + org: argv.org, + name: repoName, + }); + + log("Creating user repo", JSON.stringify(result)); + + // Push mirror? + result = await git.spawn( + [ + "push", + "--mirror", + `https://${argv.token}@github.com/${argv.org}/${ + argv.template.split("/")[1] + }-${user}`, + ], + { + cwd: `${argv.template.split("/")[1]}.git`, + } + ); + log("Pushing template to new repo", JSON.stringify(result)); + + result = await client.repos.addCollaborator({ + owner: argv.org, + repo: repoName, + username: user, + permission: "admin", + }); + log("Adding user as collaborator", JSON.stringify(result)); + + result = await client.repos.createPagesSite({ + owner: argv.org, + repo: repoName, + source: { branch: "main", path: "/docs" }, + }); + log("Enabling pages site", JSON.stringify(result)); + + result = await client.repos.update({ + owner: argv.org, + repo: repoName, + description: result.data.html_url, + }); + log( + "Updating description to show the pages URL", + JSON.stringify(result) + ); + } catch (e) { + console.error(e); + client.repos.delete({ org: argv.org, name: repoName }); + } finally { + fs.rmdirSync(`${argv.template.split("/")[1]}.git`, { + recursive: true, + }); + } + } +}; + +main(); diff --git a/scripts/package-lock.json b/scripts/package-lock.json new file mode 100644 index 0000000..c2ae753 --- /dev/null +++ b/scripts/package-lock.json @@ -0,0 +1,326 @@ +{ + "name": "t3-actions", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@npmcli/git": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.9.tgz", + "integrity": "sha512-hTMbMryvOqGLwnmMBKs5usbPsJtyEsMsgXwJbmNrsEuQQh1LAIMDU77IoOrwkCg+NgQWl+ySlarJASwM3SutCA==", + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@octokit/auth-token": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", + "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "requires": { + "@octokit/types": "^6.0.3" + } + }, + "@octokit/core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz", + "integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==", + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.4.12", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz", + "integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==", + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz", + "integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==", + "requires": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.2.3.tgz", + "integrity": "sha512-V1ycxkR19jqbIl3evf2RQiMRBvTNRi+Iy9h20G5OP5dPfEF6GJ1DPlUeiZRxo2HJxRr+UA4i0H1nn4btBDPFrw==" + }, + "@octokit/plugin-paginate-rest": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz", + "integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==", + "requires": { + "@octokit/types": "^6.11.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz", + "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==" + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.3.1.tgz", + "integrity": "sha512-3B2iguGmkh6bQQaVOtCsS0gixrz8Lg0v4JuXPqBcFqLKuJtxAUf3K88RxMEf/naDOI73spD+goJ/o7Ie7Cvdjg==", + "requires": { + "@octokit/types": "^6.16.2", + "deprecation": "^2.3.1" + } + }, + "@octokit/plugin-retry": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.7.tgz", + "integrity": "sha512-n08BPfVeKj5wnyH7IaOWnuKbx+e9rSJkhDHMJWXLPv61625uWjsN8G7sAW3zWm9n9vnS4friE7LL/XLcyGeG8Q==", + "requires": { + "@octokit/types": "^6.0.3", + "bottleneck": "^2.15.3" + } + }, + "@octokit/plugin-throttling": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.4.2.tgz", + "integrity": "sha512-BXoH4qZlISv4S25HDDya87TIWQ6L7f2ojMDblEX3GXuS3xwgLsLtJN4oRo5ZhxPfLqpoMKMZdlZkYR/0LfAbdQ==", + "requires": { + "@octokit/types": "^6.0.1", + "bottleneck": "^2.15.3" + } + }, + "@octokit/request": { + "version": "5.4.15", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz", + "integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==", + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^6.7.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz", + "integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==", + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.5.6", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.5.6.tgz", + "integrity": "sha512-8HdG6ZjQdZytU6tCt8BQ2XLC7EJ5m4RrbyU/EARSkAM1/HP3ceOzMG/9atEfe17EDMer3IVdHWLedz2wDi73YQ==", + "requires": { + "@octokit/core": "^3.2.3", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "5.3.1" + } + }, + "@octokit/types": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.16.2.tgz", + "integrity": "sha512-wWPSynU4oLy3i4KGyk+J1BLwRKyoeW2TwRHgwbDz17WtVFzSK2GOErGliruIx8c+MaYtHSYTx36DSmLNoNbtgA==", + "requires": { + "@octokit/openapi-types": "^7.2.3" + } + }, + "before-after-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz", + "integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw==" + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "npm-package-arg": { + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.4.tgz", + "integrity": "sha512-xLokoCFqj/rPdr3LvcdDL6Kj6ipXGEDHD/QGpzwU6/pibYUOXmp5DBmg76yukFyx4ZDbrXNOTn+BPyd8TD4Jlw==", + "requires": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "requires": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "requires": { + "builtins": "^1.0.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 0000000..645a35b --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,25 @@ +{ + "name": "t3-actions", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Chocrates/t3-actions.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Chocrates/t3-actions/issues" + }, + "homepage": "https://github.com/Chocrates/t3-actions#readme", + "dependencies": { + "@npmcli/git": "^2.0.9", + "@octokit/plugin-retry": "^3.0.7", + "@octokit/plugin-throttling": "^3.4.2", + "@octokit/rest": "^18.5.6" + } +}