GitHub is more than just a platform for hosting and sharing code. With millions of developers from all over the world collaborating on projects of every type and size, it has become the beating heart of the open source community. Since its foundation in 2008, GitHub has grown to host over 200 million repositories and 100 million users, with a staggering 3.5 billion contributions made in the last year alone. With GitHub Actions, engineers and developers can now automate all kinds of workflows and repetitive engineering tasks – from Continuous Integration (CI) and Continuous Deployment (CD) to IssueOps, automatic issue triaging, and ChatOps. GitHub Actions is much more than just a CI/CD tool – it’s a comprehensive automation platform that can help streamline your entire development workflow.
This book will show you how to make the most of GitHub Actions in your day-to-day life. It is a practical book – so you will do as much as possible, and I will explain the theory alongside the individual recipes.
In this chapter, you will learn the basics of workflows in GitHub: workflow files, the workflow and YAML syntax, events that trigger workflows, expressions, secrets, and environments, and you will write your first workflows.
We’re going to cover the following main topics in this chapter:
For this chapter, you will need a free GitHub account and a browser. Just sign up under https://github.com/signup if you do not have an account yet.
You will find all the recipes and example code in the repository at https://github.com/wulfland/GitHubActionsCookbook.
GitHub is built around the decentralized git
version control system (VCS), which has played a significant role in transforming the way in which software is developed. But GitHub is more than just hosting of git
repositories – it has evolved into a holistic DevOps platform with capabilities in the following areas:
From the very beginning, GitHub has prioritized a developer-centric approach, resulting in a platform that places utmost importance on webhooks and APIs. Developers can leverage either the REST or the GraphQL API to manipulate all aspects of the GitHub platform. In addition to that, developers can use GitHub as an identity provider (IdP) to access their applications. This approach facilitates seamless integration with other tools and platforms, making GitHub what it is today: the place where the world builds software.
To understand the power of GitHub Actions, one must take into account that you can use it to automate all kinds of tasks in the entire ecosystem – not just code. This includes the following:
It also integrates with all the common IDEs such as Visual Studio, Visual Studio Code, and Eclipse, and with popular chat platforms such as Slack and Teams.
npm
support – but all the other major package registries also integrate with GitHub.GitHub Actions can be used to automate tasks and build solutions across the entire GitHub ecosystem (see Figure 1.1):
Figure 1.1 – The GitHub ecosystem and its integrations
In this book, I will provide practical recipes for workflows across all the major areas so that you will be able to automate all kinds of real-world development tasks.
All the examples in this book are done on https://github.com – the Software-as-a-Service (SaaS) offering from GitHub. Signing up for GitHub is free and provides users with unlimited private and public repositories. Nearly all features on GitHub are available free for open source projects (public repositories), but they may require a paid license for private repositories. In public repos, you have unlimited minutes for actions. That’s why it is important to do all the recipes in public repos – if not, you will burn rapidly through your 2,000 minutes per month.
GitHub’s pricing model is based on a monthly per-user billing system and consists of three tiers: Free, Team, and Enterprise (see Figure 1.2):
Figure 1.2 – GitHub pricing tiers
As mentioned earlier, public repos are entirely free – including GitHub Actions, Packages, and security features such as Dependabot and Secret Scanning. Private repos are also free, but only with limited functionality for collaboration. It does not include protected branches, Codeowners, and some advanced pull request features. For private repos, you have 2,000 free minutes in the free tier. To unlock the collaboration features, you’ll need to acquire a Team license for $4 per user per month. The Team plan then also includes 3,000 minutes for GitHub Actions.
The GitHub Enterprise plan brings all the Enterprise features – such as single sign-on (SSO) with Security Assertion Markup Language (SAML) and System for Cross-domain Identity Management (SCIM), Enterprise Managed Users, and the IP allow list. It also comes equipped with 50,000 minutes for GitHub Actions – but it also costs $21 per user per month.
In addition to the SaaS offering, GitHub also provides an appliance for self-hosting – GitHub Enterprise Server (GHES). It is available for AWS, GCP, Azure, or on-premises on Hyper-V, OpenStack KVM, or VMware ESXi. GHES is only available with the Enterprise plan. You can also combine GHES with GitHub Enterprise Cloud (GHEC) and share the same license for both hosting options.
GHES and GitHub Actions
Keep in mind that you cannot use GitHub-hosted runners for your workflow if you run GHES. You will have to provide your own runners for your workflows and ensure that they are secure and clean up their workflow artifacts. Typically, this is done on Kubernetes with Actions Runner Controller (ARC – https://github.com/actions/actions-runner-controller). You will learn more about this in Chapter 4, The Workflow Runtime.
Running your workflows on self-hosted runners is completely free as you bring your own compute. Running workflows in public repositories is also free – even on the powerful runners provided by GitHub. GitHub-hosted runners are available on Linux, Windows, and macOS and in different sizes. If you want to leverage these runners in private repositories, you’ll be charged per minute. The different runners use different minute multipliers (see Table 1.1). Running a workflow on Linux will reduce 1 of your free minutes per minute – and you will be charged $0.008 if you exceed your free minutes. Windows will burn twice as fast through your free minutes and costs $0.08 per minute after that. And macOS will burn 10 times faster through your minutes and charges $0.016 per minute when you have reached the limit of your included minutes:
Operating system |
Minute multiplier |
Price per minute |
Linux |
1 |
$0.008 |
Windows |
2 |
$0.080 |
macOS |
10 |
$0.016 |
Table 1.1 – Pricing per minute for GitHub-hosted runners
That’s the reason why I use Linux for most of the examples in this book and why I always encourage my customers to run as much workload on Linux as possible.
If you use GHEC or the Team plan and you need machines with more power, then you can leverage larger GitHub-hosted runners. They are charged by minute (see Table 1.2) and have additional features such as static IP ranges:
vCPUs |
Linux |
Windows |
macOS |
2 |
$0.008 |
$0.016 |
|
3 |
$0.08 |
||
4 |
$0.016 |
||
8 |
$0.032 |
$0.064 |
|
12 |
$0.32 |
||
16 |
$0.064 |
$0.128 |
|
32 |
$0.128 |
$0.256 |
|
64 |
$0.256 |
$0.512 |
Table 1.2 – Per-minute rate for larger runners
Private networking
In addition to static IP ranges, you can also use Azure private networking to connect GitHub-hosted runners directly to your resources. At the time of writing, this feature is still in beta and might change. See the following link for more information: https://docs.github.com/en/enterprise-cloud@latest/admin/configuration/configuring-private-networking-for-hosted-compute-products/about-networking-for-hosted-compute-products.
GitHub Actions also consumes storage – for example, for logs, workflow artifacts, or caching. If you exceed your included storage, you will be billed $0.008 per GB per day.
Keep in mind that pricing may change, and refer to the GitHub documentation for up-to-date information (https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions).
And to learn GitHub Actions and experiment with workflows – just do everything in public repositories and you will not have to pay, either for compute or for storage.
GitHub offers a community-driven marketplace (https://github.com/marketplace) that contains currently more than 20,000 GitHub Actions that you can reuse as building blocks in your workflows (see Figure 1.3):
Figure 1.3 –GitHub Marketplace contains more than 20,000 reusable actions
If an action is by the author actions, that means it is a native action by GitHub. You can see the number of people who have starred an action in the overview. This will give you a good indication of the popularity of the action. And you will see the blue badge that indicates that the author of an action was verified by GitHub.
You can filter the marketplace by multiple categories, you can search by terms, and you can change the sort order of results to Most installed/starred, Best Match, or Recently added (see Figure 1.4):
Figure 1.4 – Searching in the marketplace and sorting the results
This way, it is easy to explore the marketplace and find actions that will help you automate tasks in your workflows.
If you click one of the results, it will take you to the details page of the marketplace listing (see Figure 1.5):
Figure 1.5 – Details of a marketplace listing
You can find released versions, the number of stars, contributors, and – as all published actions are open source – a link to the source repository and the number of open issues and pull requests. This should give you a good idea of how actively the action is used – and it allows you to dig into the code if you wish to do so.
The results of the marketplace are also displayed in the workflow editor, and we will use them in our recipes from it.
GitHub does a good job of guiding people in the workflow designer when writing workflows. That’s why it is best to just start and write your first workflow and familiarize yourself with the platform.
Before you can create your first workflow, you first have to create a repository on GitHub. Navigate to https://github.com/new, authenticate if you are not authenticated yet, and fill in data as in Figure 1.6:
Figure 1.6 – Creating a new repository
Pick your GitHub user as the owner and give the repo a unique name – for example, ActionsCookBook
. Make it a public repo so that all workflows and storage are free. Initialize the repo with a README file – this way, we have already files in the repo and something in the workflow to work with.
GitHub Action workflows are YAML files with a .yml
or .yaml
extension that are located in the .github/workflows
folder in a repository. You could create the file manually, but then the workflow editor would only work after the first commit. Therefore, I recommend creating a new workflow from the menu.
actions/new
). If your repository contains workflows, you will see the workflows here (as later displayed in Figure 1.16), and you would have to click the New workflow button to get to that page.On this page, you will find a lot of template workflows you could use as a starting point. There are starter workflows for deployments to most clouds, CI for most languages, security scanning of your code, automation in general, and templates to deploy content to GitHub Pages. You can filter the starter workflows by these categories. These workflows give you a good starting point for most of your workflows.
In this recipe, we will focus on familiarizing ourselves with the editor, and we will create a workflow from scratch by clicking set up a workflow yourself (see Figure 1.7):
Figure 1.7 – Creating a new workflow in GitHub
main.yml
file in .github/workflows
on the default branch and display it in the web editor. On the right side of the editor, you have the documentation, and you can search for actions
in GitHub Marketplace. In the editor, you can use Ctrl + Space (or Option + Space – depending on your keyboard settings) to trigger autocomplete. The editor will capture the Tab key and by default use it for a two-space indentation. To navigate to other controls on the page using the Tab key, you first have to exit it using Esc or using Ctrl + Shift + M.Modify the filename to MyFirstWorkflow.yml
and familiarize yourself with the editor (see Figure 1.8):
Figure 1.8 – The workflow editor for GitHub Actions
Figure 1.9 – The editor shows you all valid options at a certain level in the workflow file
Typically, workflows are started with the name
property, which sets the display name of the workflow in the UI. It’s a good practice to add a comment to the top of the file summarizing the intent of the workflow.
name
property using autocomplete. Note that the editor has error checking and indicates that you are still missing the required root key, on
(see Figure 1.10):Figure 1.10 – Error checking in the code editor
on:
, you will get a result in the JSON syntax (see the YAML collection types section); that is, on: [push]
.If you add a comma after the first element and click Control + Space again, then you can pick additional elements from autocomplete (see Figure 1.11):
Figure 1.11 – Autocomplete works also inside squared brackets
Each trigger is a map and can contain additional arguments. If you put your cursor on the line below on:
and add a two-space indentation, autocomplete will give you the results in the full YAML syntax. It will also give you properties that you can use to configure each trigger (see Figure 1.12):
Figure 1.12 – Autocomplete also helps with options for triggers
Note that most arguments – for example, branches or paths – are sequences and need a dash for each entry if you are not using the JSON syntax.
We want our test workflow to run on every push to the main
branch. We also want to be able to trigger it manually (see the Events that trigger workflows section). Your workflow code for triggers should look like this:
on: push: branches: - main workflow_dispatch:
Wildcards
The *
character can be used as a wildcard in paths and **
as a recursive wildcard. *
is a special character in YAML, so you need to use quotation marks in that case:
push:
branches:
- '
release/**'
paths:
- '
doc/**'
first_job
and go to the next line. The name of the job object can only contain alphanumeric values, a dash (-
), and an underscore (_
). If you want any other characters to be displayed in the workflow, you can use the name
property:jobs: first_job: name: My first job
ubuntu-latest
label:runs-on: ubuntu-latest
run:
command, which will execute a command-line command:steps: - name: Greet the user run: echo "Hello world" shell: bash
The name is optional and sets the output of the step in the log. The shell is also optional and will default to bash
on non-Windows platforms, with a fallback to sh
. On Windows, the default is PowerShell Core (pwsh
), with a fallback to cmd
. But you could configure any shell you want with the {0}
placeholder for the input of the step (that is, shell:
perl {0}
).
To add variable output, we can use expressions that are written between ${{
and }}
. In the expression, you can use values from context objects such as the GitHub context. Note that autocomplete also works for these context objects (see Figure 1.13):
Figure 1.13 – Autocomplete also works for context objects
Pick the actor
from the list of values:
- run: echo "Hello world from ${{ github.actor }}."
You will learn more about expressions and context syntax throughout the book. But you can refer to the documentation for expressions (https://docs.github.com/en/actions/learn-github-actions/expressions) and context (https://docs.github.com/en/actions/learn-github-actions/contexts) at any time.
|
) after run:
and write your script in the next line with a four-space indentation. YAML will treat this as one block until the next element – even with new and blank lines in it:- run: | echo "Hello world from ${{ github.actor }}." echo "Current branch is '${{ github.ref }}'."
On the right side of the workflow editor is the marketplace. You can directly search there for all kinds of actions. Search for checkout
and locate the action from actions (these are built-in actions from GitHub). In the listing, you see the owner of the action, the latest version, and the stars of the repository. The listing contains an Installation section that you can copy into your workflow to use the action (see Figure 1.14):
Figure 1.14 – Listing of the marketplace in the workflow editor
Note that many parameters are optional. To check out the repo, you only need the following lines:
- name: Checkout uses: actions/checkout@v4.1.0
Using GitHub Actions
Actions refer to a location on GitHub. The syntax is {path}@{ref}
. The path points to a physical location on GitHub and can be {owner}/{repo}
if the actions are in the root of a repository or {owner}/{repo}/{path}
if the actions are in a subfolder. The reference after @{ref}
is any git
reference that points to a commit. It can be a tag, branch, or an individual commit SHA.
- run: tree
This will output the files in the repository in a tree structure.
main
branch. Click Commit changes…, leave the commit message and branch, and click Commit changes in the dialog to finish the operation (see Figure 1.15):Figure 1.15 – Committing the workflow file
main
branch, our commit has automatically triggered the workflow. If you navigate now to Actions in your repository, you will be able to see your workflow and the latest workflow run (see Figure 1.16):Figure 1.16 – The default view in Actions displays the latest workflow runs of all workflows
Note that the name of the workflow run is the commit message. You can also see the commit that triggered the workflow and the actor that pushed the changes.
Figure 1.17 – The workflow summary page
Figure 1.18 – The workflow log for an individual job
Figure 1.19 – Triggering a workflow manually through the UI
Inspect the new workflow run and its output.
Workflow files are YAML files located in the .github/workflows
folder in a repository.
YAML stands for YAML Ain’t Markup Language and is a data-serialization language optimized to be directly writable and readable by humans. It is a strict superset of JSON but with syntactically relevant newlines and indentation instead of braces.
You can write comments by prefixing text with a hash (#
).
In YAML, you can assign a value to a variable with the following syntax: key: value
.
key
is the name of the variable. Depending on the data type of value
, the type of the variable will be different. Note that keys and values can contain spaces and do not need quotation marks! Only add them if you use some special characters or you want to force certain values to be a string. You can quote keys and values with single or double quotes. Double quotes use the backslash as the escape pattern ("Foo \"bar \" foo"
), while single quotes use an additional single quote for this ('foo ''
bar'' foo'
).
In YAML, there are two different collection types: nested types called maps and lists – also called sequences. Maps use two spaces of indentation:
parent_type: key1: value1 key2: value2 nested_type: key1: value1
A sequence is an ordered list of items and has a dash before each line:
sequence: - item1 - item2 - item3
Since YAML is a superset of JSON, you can also use the JSON syntax to put collections in one line:
key: [item1, item2, item3] key: {key1: value1, key2: value2}
There are three types of triggers for workflows: webhook triggers, scheduled triggers, and manual triggers.
Webhook triggers start the workflow based on an event in GitHub. There are many webhook triggers available. For example, you could run a workflow on an issues
event, a repository
event, or a discussions
event. The push
trigger in our example is a webhook trigger.
Scheduled triggers can run the workflow at multiple scheduled times. The syntax is the same syntax used for cron
jobs:
on: schedule: # Runs at every 15th minute - cron: '*/15 * * * *' # Runs every hour from 9am to 5pm - cron: '0 9-17 * * *' # Runs every Friday at midnight - cron: '0 2 * * FRI'
Manual triggers allow you to start the workflow manually. The workflow_dispatch
trigger will allow you to start the workflow using the web UI or GitHub CLI. You can define input parameters for this trigger using the inputs
property. The repository_dispatch
trigger can be used to trigger the workflow using the API. This trigger can also be filtered by certain event types and can accept additional JSON payload that can be accessed in the workflow.
To learn more about triggers, check the documentation at https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows.
Every job needs a runner that executes it. Runners are identified by labels. In our recipe, we use the ubuntu-latest
label. This means that our job will be executed on the latest Ubuntu image hosted by GitHub. You will learn more about runners in Chapter 4, The Workflow Runtime.
Actions refer to a location on GitHub. The syntax is {path}@{ref}
. The path points to a physical location on GitHub and can be {owner}/{repo}
if the actions are in the root of a repository or {owner}/{repo}/{path}
if the actions are in a subfolder. The reference after @{ref}
is any git
reference that points to a commit. It can be a tag, branch, or an individual commit SHA:
# Reference a version using a tag - uses: actions/checkout@v4.1.0 # Reference the current head of a branch - uses: actions/checkout@main # Reference a specific commit - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
For local actions in the same repository, you can omit the reference if you check out of the repository.
If the action has defined inputs, you can specify them using the with
property:
- uses: ActionsInAction/HelloWorld@v1 with: WhoToGreet: Mona
Inputs can be optional or required. You can also set environment variables for steps using the env
property:
- uses: ActionsInAction/HelloWorld@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
This is just a very basic workflow that uses an action to check out code and runs some commands on the command line. In the next two recipes, I’ll show you how to use secrets, variables, and protected environments for more complex workflows.
You can set variables and secrets in a repository that you can access in workflows. In this recipe, we’ll add both and access them in the workflow.
In this recipe, we will use the web UI to set variables and secrets. You can also use the GitHub CLI (https://cli.github.com/) for that. If you want to try that, then you have to install it. But it is not necessary for following the recipe.
settings/secrets/actions
) and Variables (settings/variables/actions
; see Figure 1.20):Figure 1.20 – Configuring secrets and variables for a repository
settings/secrets/actions/new
; see Figure 1.21):Figure 1.21 – Adding a new secret
Add MY_SECRET
as the secret name and a random word such as Abracadabra
as the secret, and click Add secret. The secret will be masked in the logs! So, don’t use a common word that could occur in other outputs of random jobs or steps.
Naming conventions for secrets and variables
Secret names are not case-sensitive, and they can only contain normal characters ([a-z]
and [A-Z]
), numbers ([0-9]
), and an underscore (_
). They must not start with GITHUB_
or a number.
The best practice is to name secrets with uppercase words separated by the underscore character.
settings/variables/actions/new
) and create a WHO_TO_GREET
variable with the value World
..github/workflows/MyFirstWorkflow.yml
file from the previous recipe and click the edit icon (see Figure 1.22):Figure 1.22 – Editing MyFirstWorkflow.yml
Change the word World
to the ${{ vars.WHO_TO_GREET }}
expression and add a new line using the ${{ secrets.MY_SECRET }}
secret:
- run: | echo "Hello ${{ vars.WHO_TO_GREET }} from ${{ github.actor }}." echo "My secret is ${{ secrets.MY_SECRET }}."
Figure 1.23 – Output of a secret and variable in the log
You can create configuration variables for use across multiple workflows by defining them on one of the following levels:
The three levels work like a hierarchy: you can override a variable or secret on a lower level by providing a new value to the same key. Figure 1.24 illustrates the hierarchy:
Figure 1.24 – The hierarchy for configuration variables and secrets
Secrets and variables for organizations work the same way as for repositories. You can create a secret or variable under Settings | Secrets and variables | Actions. New organization secrets or variables can have an access policy for the following:
When choosing Selected repositories, you can grant access to individual repositories.
In addition to setting these values through the UI, it is also possible to use the GitHub CLI.
You can use gh secret
or gh variable
to create new entries:
$ gh secret set secret-name $ gh variable set var-name
You will be prompted for the secret or variable values, or you can read the value from a file, pipe it to the command, or specify it as the body (-b
or --body
):
$ gh secret set secret-name < secret.txt $ gh variable set var-name --body config-value
Environments are used to describe a general deployment target such as development
, test
, staging
, or production
. You can protect environments with protection rules, and you can provide configuration variables and secrets for specific environments.
We will first create some environments using the web UI and add some protection rules, secrets, and variables. Then, we add them to our existing workflow.
Figure 1.25 – Managing environments in a repository
Enter the name Production
and click Configure environment (see Figure 1.26):
Figure 1.26 – Creating a new environment
Figure 1.27 – Configuring deployment protection rules
main
branch (see Figure 1.28):Figure 1.28 – Configuring deployment branches and tags
MY_SECRET
secret with the value Open Sesame
(see Figure 1.29). Repeat this with Add variable and add a WHO_TO_GREET
variable with the value Production users
:Figure 1.29 – Adding secrets and variables to environments
Test
and Load-Test
. We will use these environments in the next steps to show how to execute jobs in parallel. You don’t have to configure deployment branches or required reviewers. Just add a WHO_TO_GREET
variable with the corresponding value. The result should look like Figure 1.30:Figure 1.30 – Multiple environments in the settings of the repository
first_job
called Test
that runs on the latest Ubuntu image. We associate this job with the Test
environment. To run this job after first_job
, we use the needs
property and set it to the job we depend on:Test: runs-on: ubuntu-latest environment: Test needs: first_job
To see how secrets are overwritten by the environment, we have to use a little hack. As GitHub searches for the value of secrets in the output of the log to mask it, we have to modify the actual text. We can do this, for example, using the sed 's/./& /g'
command. This will add a blank between every character of the secret. With this little hack, the steps of the Test
job should look like this:
steps: - run: | echo "Hello ${{ vars.WHO_TO_GREET }} from ${{ github.actor }}." sec=$(echo ${{ secrets.MY_SECRET }} | sed 's/./& /g') echo "My secret is '$sec'."
Load-Test
job that is associated with the Load-Test
environment and also executes after first_job
:Load-Test: runs-on: ubuntu-latest environment: Load-Test needs: first_job
Just copy the steps from Test
. There is no need to change anything.
Production
job. In addition to the name, the environment
property accepts a URL that later will be displayed in the workflow designer. Set it to any URL you want. To show how after a parallel execution of jobs the workflow can merge again, we will run Production
after Test
and Load-Test
:Production: runs-on: ubuntu-latest environment: name: Production url: https://writeabout.net needs: [Test, Load-Test]
Just copy the steps from the previous jobs.
main
branch. The workflow will run automatically. Navigate to the new workflow run and inspect the workflow designer, which nicely shows the parallel execution. The workflow will pause before executing Production
and will wait for approval (see Figure 1.31):Figure 1.31 – The workflow will stop before an environment with required reviewers and wait for approval
Production
job (see Figure 1.32):Figure 1.32 – Approving a protected environment
The workflow will execute completely, and the result should look like Figure 1.33. Note that the URL is displayed in the Production environment. Also, note the history of approvals in the workflow summary:
Figure 1.33 – The final summary of the workflow
Open the individual jobs and inspect the output of the step we added (see Figure 1.34). The secrets and variables are used from the repository and are only overridden if we set them in an environment:
Figure 1.34 – The production secret is only available to the production environment after approval
If you are setting secrets or variables for an environment using the GitHub CLI, then you can specify them using the --env
(-e
) argument. For organization secrets, you set the visibility (--visibility
or -v
) to all
, private
, or selected
. For selected
, you must specify one or more repos using --
repos
(-r
):
$ gh secret set secret-name --env environment-name $ gh secret set secret-name --org org -v private $ gh secret set secret-name --org org -v selected -r repo
Environments have more options than we have used in this recipe. You can also configure a wait timer that will pause the workflow for n minutes (with a maximum of 30 days) before executing the deployment job for that particular environment.
There is also a new feature called custom deployment protection rules that is still in beta. This feature allows the creation of GitHub apps that can pause your deployment and wait for a specific condition. There are already apps from Datadog, Honeycomb, Sentry, New Relic, and ServiceNow (see https://docs.github.com/en/actions/deployment/protecting-deployments/configuring-custom-deployment-protection-rules#using-existing-custom-deployment-protection-rules). We’ll have a closer look at custom deployment rules in Chapter 7, Release Your Software with GitHub Actions.
The true power of environment protection rules lies in the deployment branch or tag rules. This can restrict code that does not apply to branch protection rules from deploying to certain environments. This can include all kinds of checks – Codeowners approvals, code reviewers, deployments to certain other environments, SonarQube quality gates, and many other automated code checks (see https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches for more information).
Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.
If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.
Please Note: Packt eBooks are non-returnable and non-refundable.
Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:
If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:
Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.
You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.
Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.
When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.
For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.