SlideShare a Scribd company logo
Learning Github Actions Automation And
Integration Of Cicd With Github 1st Edition
Brent Laster download
https://ebookbell.com/product/learning-github-actions-automation-
and-integration-of-cicd-with-github-1st-edition-brent-
laster-52341142
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Learning Github Actions 1 Converted Brent Laster
https://ebookbell.com/product/learning-github-actions-1-converted-
brent-laster-51775146
Learning Github Actions Second Early Release Brent Laster
https://ebookbell.com/product/learning-github-actions-second-early-
release-brent-laster-46543062
Learning Github Actions Brent Laster
https://ebookbell.com/product/learning-github-actions-brent-
laster-232271096
Aiassisted Programming For Web And Machine Learning Improve Your
Development Workflow With Chatgpt And Github Copilot Christoffer
Noring
https://ebookbell.com/product/aiassisted-programming-for-web-and-
machine-learning-improve-your-development-workflow-with-chatgpt-and-
github-copilot-christoffer-noring-59791118
Machine Learning Simplified A Gentle Introduction To Supervised
Learning 1011 Andrew Wolf
https://ebookbell.com/product/machine-learning-simplified-a-gentle-
introduction-to-supervised-learning-1011-andrew-wolf-42568766
Learning
https://ebookbell.com/product/learning-35537428
Learning Cognitivebehavior Therapy An Illustrated Guide 2nd Edition
2nd Edition Jesse H Wright
https://ebookbell.com/product/learning-cognitivebehavior-therapy-an-
illustrated-guide-2nd-edition-2nd-edition-jesse-h-wright-44880782
Learning Tagalog Fluency Made Fast And Easy Course Book 1 Part Of
7book Set 2nd Edition Frederik De Vos
https://ebookbell.com/product/learning-tagalog-fluency-made-fast-and-
easy-course-book-1-part-of-7book-set-2nd-edition-frederik-de-
vos-44939110
Learning Tagalog Fluency Made Fast And Easy Course Book 3 Part Of
7book Set Bw Free Audio Download 2nd Edition Frederik De Vos
https://ebookbell.com/product/learning-tagalog-fluency-made-fast-and-
easy-course-book-3-part-of-7book-set-bw-free-audio-download-2nd-
edition-frederik-de-vos-44939112
Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster
Brent Laster
Foreword by Julian C. Dunn
Learning
GitHub Actions
Automation and Integration of CI/CD with GitHub
GITHUB
“Whether you are new to
CI/CD and starting with
GitHub Actions as your
first product in this space
or are already a CI/CD
expert and migrating
from another tool, Brent’s
book has the right
balance of information
to help you become
productive quickly.”
—Julian C. Dunn
Senior Director of Project
Management, GitHub Actions
”If you’re looking to
master automation in
software development,
Learning GitHub Actions
is a comprehensive guide
you can’t miss.”
—Taylor Dolezal
Head of Ecosystem, CNCF
Learning GitHub Actions
Twitter: @oreillymedia
linkedin.com/company/oreilly-media
youtube.com/oreillymedia
Maximize your software development productivity with
GitHub Actions, the continuous integration and automation
platform that works seamlessly with GitHub. With this practical
book, author Brent Laster shows software developers, SREs,
and DevOps engineers how to gain the maximum benefit
from Actions. You’ll learn how to leverage this feature in your
daily work with GitHub to achieve greater simplification,
standardization, and automation.
This book explains the platform, components, use cases,
implementation, and integration points of actions, so you
can leverage them to provide the functionality and features
that today’s complex pipelines and software development
processes need. You’ll learn how to design and implement
automated workflows that respond to common events like
pushes, pull requests, and review updates—and how to use
Actions to implement functionality from simple validation
to complex pipelines.
You’ll learn how to:
• Understand the structure, syntax, and semantics of
GitHub Actions
• Incorporate actions into your automation and processes
• Create custom actions with Docker, JavaScript, or
shell approaches
• Troubleshoot and debug workflows that use actions
• Combine actions with GitHub APIs and other
integration options
• Securely implement workflows with GitHub Actions
• Migrate from using other CI/CD platforms to GitHub Actions
Brent Laster is an R&D DevOps
director at SAS. He is a global
trainer, author, and speaker on
open source technologies.
US $65.99 CAN $82.99
ISBN: 978-1-098-13107-4
Brent Laster
Foreword by Julian C. Dunn
Learning GitHub Actions
Automation and Integration
of CI/CD with GitHub
Boston Farnham Sebastopol Tokyo
Beijing Boston Farnham Sebastopol Tokyo
Beijing
978-1-098-13107-4
[LSI]
Learning GitHub Actions
by Brent Laster
Copyright © 2023 Tech Skills Transformations, LLC. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
also available for most titles (https://oreilly.com). For more information, contact our corporate/institu‐
tional sales department: 800-998-9938 or corporate@oreilly.com.
Acquisitions Editor: John Devins
Development Editor: Michele Cronin
Production Editor: Jonathon Owen
Copyeditor: Piper Editorial Consulting, LLC
Proofreader: Kim Wimpsett
Indexer: Ellen Troutman-Zaig
Interior Designer: David Futato
Cover Designer: Karen Montgomery
Illustrator: Kate Dullea
August 2023: First Edition
Release History for the First Edition
2023-08-16: First Release
See https://oreilly.com/catalog/errata.csp?isbn=9781098131074 for release details.
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Learning GitHub Actions, the cover
image, and related trade dress are trademarks of O’Reilly Media, Inc.
The views expressed in this work are those of the author and do not represent the publisher’s views. While
the publisher and the author have used good faith efforts to ensure that the information and instructions
contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or
omissions, including without limitation responsibility for damages resulting from the use of or reliance
on this work. Use of the information and instructions contained in this work is at your own risk. If any
code samples or other technology this work contains or describes is subject to open source licenses or the
intellectual property rights of others, it is your responsibility to ensure that your use thereof complies
with such licenses and/or rights.
To all my family and friends who have helped me write the best chapters of my life.
Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster
Table of Contents
Foreword. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Part I. Foundations
1. The Basics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
What Is GitHub Actions? 4
Automation Platform 4
Framework 5
What Are the Use Cases for GitHub Actions? 6
Starter Workflows 7
Actions Marketplace 8
What Costs Are Involved? 10
The Free Model 10
The Paid Model 10
When Does Moving to GitHub Actions Make Sense? 13
Investment in GitHub 13
Use of Public Actions 13
Creating Your Own Actions 13
Artifact Management 13
Action Management 14
Conclusion 14
2. How Does Actions Work?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
An Overview 15
Triggering Workflows 17
v
Components 19
Steps 19
Runners 20
Jobs 20
Workflow 21
Workflow Execution 22
Conclusion 24
3. What’s in an action?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
The Structure of an action 26
Interfacing with actions 29
Using actions 32
Public actions and the Marketplace 32
Conclusion 36
4. Working with Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Creating the First Workflow in a Repository 37
Committing the Initial Workflow 42
Using the VS Code GitHub Actions Extension 59
Conclusion 65
5. Runners. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
GitHub-Hosted Runners 67
What’s in the Runner Images? 69
Adding Additional Software on Runners 71
Self-Hosted Runners 72
Requirements for Self-Hosted Runners 73
Limits for Self-Hosted Runners 74
Security Considerations for Using Self-Hosted Runners 74
Setting Up a Self-Hosted Runner 75
Using a Self-Hosted Runner 78
Using Labels with Self-Hosted Runners 79
Troubleshooting Self-Hosted Runners 80
Removing a Self-Hosted Runner 82
Autoscaling Self-Hosted Runners 86
Just-in-Time Runners 86
Conclusion 86
vi | Table of Contents
Part II. Building Blocks
6. Managing Your Workflow Environments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Naming Your Workflow and Workflow Runs 91
Contexts 93
Environment Variables 94
Default Environment Variables 95
Secrets and Configuration Variables 97
Managing Permissions for Your Workflow 103
Deployment Environments 105
Conclusion 115
7. Managing Data Within Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Working with Inputs and Outputs in Workflows 118
Defining and Referencing Workflow Inputs 118
Capturing Output from a Step 119
Capturing Output from a Job 120
Capturing Output from an Action Used in a Step 121
Defining Artifacts 122
Uploading and Downloading Artifacts 123
Adding Parameters 127
Using Caches in GitHub Actions 135
Using the Explicit Cache Action 136
Monitoring Caches 141
Activating a Cache with a Setup Action 143
Conclusion 145
8. Managing Workflow Execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
Advanced Triggering from Changes 147
Triggering Based on Activity Types 148
Using Filters to Refine Triggers 150
Triggering Workflows Without a Change 152
Dealing with Concurrency 156
Running a Workflow with a Matrix 159
Workflow Functions 160
Conditionals and Status Functions 161
Conclusion 163
Table of Contents | vii
Part III. Security and Monitoring
9. Actions and Security. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Security by Configuration 168
Managing Execution of Workflows from Pull Requests 173
Workflow Permissions 174
The CODEOWNERS File 175
Protected Tags 176
Protected Branches 177
Repository Rules 178
Security by Design 181
Secrets 181
Securing Secrets 182
Tokens 183
Dealing with Untrusted Input 191
Securing Your Dependencies 199
Security by Monitoring 201
Scanning 202
Processing Pull Requests Securely 205
Vulnerabilities with Workflows in Pull Requests 207
Vulnerabilities with Source Code in Pull Requests 212
Adding a Pull Request Validation Script 215
Safely Handling Pull Requests 218
Conclusion 220
10. Monitoring, Logging, and Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Gaining More Observability 223
Understanding Status at a High Level 224
Creating Status Badges for Workflows 226
Working with Past States 232
Mapping Workflow Versions to Runs 232
Re-running Jobs in a Workflow 234
Debugging Workflows 241
Step Debug Logging 242
Debugging the Runner Environment 245
Activating Debugging 248
Augmenting and Customizing Logging 249
Adding Your Own Messages in Logs 249
Additional Log Customizations 251
Creating a Customized Job Summary 253
Conclusion 256
viii | Table of Contents
Part IV. Advanced Topics
11. Creating Custom actions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Anatomy of an action 260
Types of Actions 263
Composite Action 263
Docker Container Action 267
Creating a JavaScript Action 271
Completing Your Action Creation 274
Publishing Actions on the GitHub Marketplace 276
Updating Actions on the Marketplace 282
Removing an Action from the Marketplace 285
The Actions Toolkit 285
Using Workflow Commands from the Toolkit 286
Local actions 289
Conclusion 291
12. Advanced Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
Creating Your Own Starter Workflows 293
Creating a Starter Workflow Area 295
Creating a Starter Workflow File 295
Adding Supporting Pieces 297
Using the New Starter Workflow 299
Reusable Workflows 300
Inputs and Secrets 303
Outputs 305
Limitations 306
Required Workflows 308
Constraints 308
Example 309
Execution 313
Conclusion 315
13. Advanced Workflow Techniques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Driving GitHub from Your Workflow 317
Using the GitHub CLI 318
Creating Scripts 319
Invoking GitHub APIs 320
Using a Matrix Strategy to Automatically Create Jobs 322
One-Dimensional Matrices 322
Multi-dimensional Matrices 323
Including Extra Values 327
Table of Contents | ix
Excluding Values 328
Handling Failure Cases 329
Defining Max Concurrent Jobs 330
Using Containers in Your Workflow 330
Using a Container as the Environment for a Job 331
Using a Container with a Step 333
Running Containers as Services in a Job 334
Conclusion 335
14. Migrating to GitHub Actions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Prep 338
Source Code 338
Automation 340
Infrastructure 340
Users 341
Azure Pipelines 342
CircleCI 344
GitLab CI/CD 346
Jenkins 348
Travis CI 351
GitHub Actions Importer 353
Authentication 354
Planning 355
Build Steps and Related 357
Manual Tasks 359
File Manifest 360
Forecasting 361
Doing a Dry Run 363
Creating Custom Transformers for the Importer 364
Doing the Actual Migration 369
Conclusion 373
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
x | Table of Contents
Foreword
The fundamental concepts of continuous integration/continuous delivery (CI/CD)
have now been around for several decades, since Martin Fowler and Matthew Foem‐
mel of Thoughtworks first popularized CI in their seminal essay of September 2000,
and Jez Humble and Dave Farley wrote about CD in their 2010 book Continuous
Delivery: Reliable Software Releases Through Build, Test, and Deployment Automation
(Addison-Wesley Professional). Yet it has taken years for widespread adoption of
tools for CI/CD and for the notion of a software delivery pipeline to take root. I
believe this is because three fundamental socio-technical changes in how we do soft‐
ware development had to occur first:
• Development had to become collaborative, rather than performed by isolated,
individual engineers. This was driven first by a truly distributed version control
system (Git) and then accelerated through pull-request platforms like GitHub.
• Widespread adoption of agile practices needed to occur. Motivated by metrics
from DevOps leaders like DevOps Research Associates (DORA) that, contrary to
intuition, showed more frequent delivery of smaller changes reduces risk, savvy
engineering leaders drove the implementation of frequently used build pipelines
where software was continuously built, tested, and deployed directly to custom‐
ers—sometimes dozens of times per day.
• The overburdening of traditional IT operations functions with increased com‐
plexity drove massive cultural changes via the DevOps movement. This led to a
you-build-it, you-own-it approach to software operations where, increasingly,
developers take full ownership for the success, failure, and performance of their
software in production, rather than throwing code over the wall to a release engi‐
neering team that would operate a build process and somehow “add quality” to
software that didn’t have it already.
All these changes mean that GitHub Actions, as a relatively recent entrant to the
CI/CD pipeline and automation category, is a substantially different product from
xi
incumbents. It is natively integrated into GitHub, making it a natural fit for develop‐
ers who are already familiar with storing their source code there. GitHub Actions is
also designed around the concept of a workflow, which can be used to create CI/CD
pipelines but also handle any other kind of software automation tasks like managing
open issues and tasks that open source and enterprise developers alike need to per‐
form in the course of their work. Finally, GitHub Actions, as the name would suggest,
is based on the notion of an action: a reusable component that helps to encapsulate
common tasks and reduce repetition when authoring workflows. The GitHub Mar‐
ketplace offers nearly 20,000 actions at the time of writing, making it easy for devel‐
opers, DevOps engineers, and site reliability engineers to get started with any kind of
build automation task.
Although GitHub Actions is a sophisticated product, learning it doesn’t need to be
complicated. Brent Laster has written an excellent book that relies on progressive dis‐
closure, starting with the most basic concepts to get you up and running with GitHub
Actions while also providing a comprehensive tour of GitHub Actions’ most
advanced features to help you to optimize your use of the product as you adopt it
across your organization. My team and I have been delighted to partner with Brent in
ensuring that the content covered here is as current as possible. Whether you are new
to CI/CD and starting with GitHub Actions as your first product in this space or are
already a CI/CD expert and migrating from another tool, Brent’s book has the right
balance of information to help you become productive quickly.
We wish you the greatest success in automating your software delivery processes.
— Julian C. Dunn
Senior Director of Product Management
GitHub Actions
xii | Foreword
Preface
Releasing software should be easy.… Automate almost everything, and keep everything you
need to build, deploy, test, and release your application in version control.
—David Farley, Continuous Delivery: Reliable Software Releases Through Build, Test,
and Deployment Automation
Back in 1968, the London Underground in the United Kingdom needed a digital sign
to warn passengers to be careful while crossing the gaps between train doors and sta‐
tion platforms. Since data storage for such signs was very expensive back in the day,
they chose a very short phrase to help keep riders alert: “mind the gap.”
These days, the word “mind” is less commonly used, but the intent to bring awareness
to missing parts or things that can trip you up and to act on them is still meaningful.
And it is just as important when we apply the idea to business and technical processes
that can benefit from automation.
From its inception in 2008, GitHub has filled gaps in terms of allowing users to col‐
laborate and build communities around open source software. And it has done this
very well. It is challenging not to overestimate the significance of the SaaS hosting
model that GitHub pioneered and the collaborative ecosystem it has built around it.
Yet up until a few years ago, there was one key piece of that ecosystem that was clearly
missing—a tightly integrated automation platform for key functions like CI/CD.
Certainly, there has been no shortage of applications that have worked to fill that gap.
Tools such as Jenkins, Travis CI, CircleCI, Azure DevOps, and more have provided
integration methods through various approaches such as webhooks. However, users
of GitHub still had to go outside their collaboration environment to use another
application to get the basic functionality they needed. All of that has changed with the
addition of GitHub Actions.
Actions is challenging to classify with a standalone designation. It is a logical exten‐
sion of the larger GitHub model. And while this is not a general book on GitHub, I
have tried to write it in such a way that you can see how GitHub Actions plays with
xiii
the larger GitHub ecosystem, regardless of your experience level with automation in
GitHub.
The Structure of This Book
Since you’re reading this book, I imagine you’re at least somewhat curious and per‐
haps even excited about the potential of Actions. I’ve tried to capture that potential
along with the relevant details throughout the text. So let me tell you a bit about the
organization of this Learning GitHub Actions book and how you can get the most out
of it.
Part I: Foundations
As with any technical journey, we start off discussing the foundations of GitHub
Actions. Part I of the book covers the basics of what GitHub Actions is and how it
works, and it helps you understand its core pieces and how to navigate its flow. My
intent here is to answer the basic why and how questions that you need to know to
get up and running with the technology, while providing you the insight and under‐
standing to establish the firm footing to launch your use of actions on.
Part II: Building Blocks
Part II extends your depth of knowledge on Actions with the building blocks to take
advantage of the wider range of options available to you for configuration, sharing
and storing data, and triggering and controlling the execution of your workflows.
These techniques form the core of using actions to get your tasks done, while show‐
ing you how to customize their use to best suit your needs.
Part III: Security and Monitoring
Use of a technology includes the explicit requirement to use it securely. And the need
to understand the security aspects of any new technology is critical. So Part III of the
book discusses the key areas of security and monitoring. This section looks at security
from the triple lenses of configuration, design, and monitoring. Then it further delves
into monitoring in its own right, by describing the different options available for log‐
ging and the techniques available to you for debugging issues.
Part IV: Advanced Topics
When you’re ready for more advanced interaction with Actions, Part IV provides
insight on a number of less typical (but arguably more fun) topics. These include cre‐
ating your own custom actions, creating your own starter workflows and reusable
workflows, working with the GitHub CLI, APIs, and using matrix strategies and con‐
tainers in your workflows. And to finish up, I’ve included some practical tips and
xiv | Preface
examples of how to migrate to GitHub Actions if you’re using another automation
toolset. The book’s last chapter also includes an in-depth review and examples of the
new GitHub Importer tool to help bootstrap and automate migrations.
With this general structure in mind, the next section provides a further breakdown
by audience type.
Intended Audience
This book is for anyone who is trying to learn more about GitHub Actions. If you’re
picking this book up, you should already have a basic knowledge of Git and GitHub,
and now you’re trying to figure out how to implement Actions into your workflow.
You likely have some experience with solutions like Jenkins, Travis CI, and so on, and
the automation platform and framework of GitHub Actions may improve your soft‐
ware development lifecycle process.
You might be a software developer, SRE, DevOps engineer, or something else entirely,
but it is my hope that the sections outlined above will provide a complete learning
solution for GitHub Actions for all readers. Here are some audiences that I had in
mind while writing it and that I think can benefit from it:
• Those who are new (or newish) to GitHub and looking to understand how the
automation component of it works
• Those who already understand the concepts and flow of GitHub Actions and
want or need assistance with actually implementing the code and syntax for
workflows
• Those who want to understand and evaluate GitHub Actions as a potential
CI/CD/automation target
• Those who already have some experience with GitHub Actions and want to lev‐
erage it more fully for custom purposes
• Those who are working on implementing or have implemented GitHub Actions
and need to make sure they do it securely
• Those who are responsible for, or want to, roll out GitHub Actions across a
department, organization, or unit
• Those who are experienced GitHub users and want to migrate their current
CI/CD solutions to GitHub Actions
If one of these fits your use case, I hope the book will provide you with the value
you’re looking for. If you read it and have the opportunity, feedback is always wel‐
come through reviews or interactions at future conferences or training venues.
Preface | xv
Continuing with GitHub Actions
Of course, technology continues to evolve, and we can predict it will evolve more
quickly in some areas than in others. Thus you will notice that some sections of the
text include disclaimers that reference “as of the time of writing.” While GitHub and I
have worked together to make this book comprehensive and as current as possible as
of the time of writing, you should always consult the current GitHub documentation
to get the most timely information—especially on features that are currently marked
beta. Fortunately, the text contains many links to the current GitHub documentation
for relevant areas.
Over a decade of use in various forms has shown that continuous, automated pro‐
cesses are durable models in the industry, proving out their long-term potential, relia‐
bility, and adaptability. Over time, the tooling will change, and the inputs will change,
and the steps will evolve. But a well-done CI/CD/automation framework will always
provide the best means to produce software in a timely manner to meet the demands
of the users. If you are working in GitHub, you can find no better framework to
achieve that goal than GitHub Actions.
I hope that this book helps you mind the gaps in your knowledge of GitHub Actions
and fill them all in. Best of luck in your journey and thank you for reading.
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program ele‐
ments such as variable or function names, databases, data types, environment
variables, statements, and keywords.
This element signifies a general note.
This element indicates a warning or caution.
xvi | Preface
Using Code Examples
Supplemental material (code examples, exercises, etc.) is available for download at
https://github.com/techupskills/learning-github-actions.
If you have a technical question or a problem using the code examples, please send
email to support@oreilly.com.
This book is here to help you get your job done. In general, if example code is offered
with this book, you may use it in your programs and documentation. You do not
need to contact us for permission unless you’re reproducing a significant portion of
the code. For example, writing a program that uses several chunks of code from this
book does not require permission. Selling or distributing examples from O’Reilly
books does require permission. Answering a question by citing this book and quoting
example code does not require permission. Incorporating a significant amount of
example code from this book into your product’s documentation does require
permission.
We appreciate, but generally do not require, attribution. An attribution usually
includes the title, author, publisher, and ISBN. For example: “Learning GitHub
Actions by Brent Laster (O’Reilly). Copyright 2023 Tech Skills Transformations, LLC,
978-1-098-13107-4.”
If you feel your use of code examples falls outside fair use or the permission given
above, feel free to contact us at permissions@oreilly.com.
O’Reilly Online Learning
For more than 40 years, O’Reilly Media has provided technol‐
ogy and business training, knowledge, and insight to help
companies succeed.
Our unique network of experts and innovators share their knowledge and expertise
through books, articles, and our online learning platform. O’Reilly’s online learning
platform gives you on-demand access to live training courses, in-depth learning
paths, interactive coding environments, and a vast collection of text and video from
O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com.
Preface | xvii
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-889-8969 (in the United States or Canada)
707-829-7019 (international or local)
707-829-0104 (fax)
support@oreilly.com
https://www.oreilly.com/about/contact.html
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at https://oreil.ly/learning-github-actions.
For news and information about our books and courses, visit https://oreilly.com.
Find us on LinkedIn: https://linkedin.com/company/oreilly-media
Follow us on Twitter: https://twitter.com/oreillymedia
Watch us on YouTube: https://youtube.com/oreillymedia
Acknowledgments
Writing a book is a serious investment. Throughout the duration of writing this one, I
have invested many early mornings, late nights, and weekends researching and craft‐
ing the content. But as Learning GitHub Actions nears publication, I am also
reminded of the many others who have invested their time and energy to help get it
from idea to print. It is my hope that these collective efforts ultimately lead to you
feeling that it is worthy of the investment you are making by reading it.
I can’t thank everyone involved enough for their commitment to this project, and
their support, but I will try. It has been well over a year since I first started typing out
Chapter 1, and many of the individuals mentioned here have been along for all, or the
biggest part, of the journey. (And if you were involved in the journey and I neglected
to acknowledge you here, please excuse the oversight. I can assure you it is an unin‐
tentional cognitive slip rather than an intentional slight.)
First, many thanks to John Devins, my acquisitions editor at O’Reilly who believed in,
and advocated for, this book—as he has done on my behalf for so many other
projects. I have truly come to respect and appreciate John’s vision and desire to pro‐
vide quality training opportunities and find new ways to bridge learning gaps. John is
most often behind the scenes, but his efforts are core to much of the learning that I
and other content creators get to bring to the attendees of O’Reilly Learning.
xviii | Preface
Also behind the scenes, Michele Cronin has worked tirelessly as the development edi‐
tor for this project, keeping it (and me) on track, helping resolve any potential road‐
blocks, and giving me sage advice on how to navigate any and all challenges that have
come up along the way. Her advice has always been relevant and what I needed to
hear at the time. But perhaps most impressive is that she has always done it with a
smile on her face, as an optimistic and supportive guide in the process. I will honestly
say that I have never been a fan of the editing part of writing books. But with Michele,
I knew I would come away with a confident sense of how to proceed based on her
experience and guidance.
There are numerous other people at O’Reilly that have had a hand in the book pro‐
cess that I want to also call out. Kate Dullea did a yeoman’s share of work in reviewing
all of the screenshots and images going into the book to make sure they were suitable
and legible. She also provided invaluable tips for me to validate them as I was creating
the content. Clare Laylock, Kim Sandoval, and Jonathan Owen have been exceptional
in proofreading and clarifying the content to make it clear and readable. And thanks
to Karen Montgomery for the cool cover picture and David Futato for the interior
design.
I next need to thank Julian C. Dunn, senior director of product management for
Actions at GitHub. In any extended discussion on a technology that is supported by a
company as well as a community, it is incredibly helpful to have a contact point who
can help you understand the current and future direction of the technology, answer
questions, and dispel confusion around topics. Julian has done all that and more as a
reviewer and advisor while I’ve been building out the content. His collaboration has
unquestionably helped the book become a better, more relevant text. My appreciation
goes to Julian and GitHub for their active participation in making sure the content is
the best and most up to date it can be as of the time of writing. (I should also note
that he wrote the foreword for the book, which I hope you’ll take a moment to read if
you haven’t already.)
Along with Julian, I could not have asked for a better team of technical reviewers than
Brent Beer, Taylor Dolezal, Kerim Satirli, and Daniel Hinojosa. Each provided very
useful feedback and suggestions that helped to keep me straight on the technical top‐
ics and presentation of the material. I feel very fortunate that I was able to get the
investment of time from this group and get the benefit of their collective technical
backgrounds and collective eyes for detail.
I also want to thank Ethan Dennis from GitHub for his collaboration on the Actions
Importer tooling and process. I was very excited when I found out that this unique
new tool existed. I knew quickly that the book needed to include it as part of the final
chapter on migration. Ethan was incredibly helpful as I worked through examples
and the use of the tool, quickly addressing any questions and issues I ran into and
Preface | xix
serving as a reviewer for that chapter. His efforts and involvement are much
appreciated.
As I mentioned earlier, the work on this book was done mainly on mornings and
weekends—outside of my full-time job as a director in the DevOps organization at
SAS. But it is only because of the support of my coworkers and management at SAS
that I am able to keep my feet in both the corporate and open source worlds. I espe‐
cially want to thank Rob Stephens for his mentorship on getting things done, his
attempts to help me learn to write concisely for business communications (which I
am still working towards), and his support for leveraging my training and writing
interests as a part of my job at SAS. Also thanks to Jared Peterson for his leadership,
support, and focus on open-source opportunities, and Bryan Harris—our incredible
CTO and EVP—for his examples of technical and people leadership and support.
I would be remiss not to give a shout-out here to Todd Lewis, chairman of the All
Things Open organization, and Jay Zimmerman, director of the No Fluff Just Stuff
conferences, for providing me with opportunities to speak and present at their
respective conferences over the years. The material in this book is better because of
the many presentations I’ve done on related topics in virtual workshops and confer‐
ences for ATO and NFJS since I started learning about Actions. If you ever have a
chance to attend one of these conferences or a meetup or virtual event sponsored by
these organizations, I encourage you to do so.
On a lighter note, thanks to “the gang” (you know who you are), who meet for team
building every week at Rally Point (building RP) after work. This is one of the few
chances I get to relax while enjoying the conversation and unwinding with people
who are not only current and past coworkers, beer aficionados, world philosophers,
and technical gurus, but also friends.
Most importantly, I want to thank my wife, Anne-Marie, for being my soulmate and
always supporting me in everything I do. Through her and our kids, Walker, Chase,
Tanner, and Katie, I am constantly reminded that the people and relationships, espe‐
cially family, that we have in our lives are the most important thing. Everything else is
simply a means to an end—or should be—to get the time to make the connections
and share experiences with our family and friends.
Finally, thanks to you, the reader, for getting this book and reading it. I sincerely hope
that you will find it useful and something that helps you achieve the goals that you’re
looking for as you start or continue your journey with GitHub Actions.
xx | Preface
PART I
Foundations
Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster
CHAPTER 1
The Basics
Welcome to Learning GitHub Actions. I’m excited that you’re here and for all that
you’re about to learn. This is an amazing time to be working in the software field.
From containers to clusters to clouds, from automation to generative AI, from secu‐
rity to SREs, the opportunities to create and contribute to interesting software
projects has never been greater. And thanks to powerful platforms such as GitHub,
that creation and contribution has never been easier to do.
GitHub has led the field in developing an ecosystem for managing the components of
software and enabling collaboration, as witnessed by the vast number of open-source
projects managed in its repositories. And it has continually provided additional value
for users through enhancements to its interfaces, tracking contributions and issues,
mechanisms to publish and share information, and much more.
For the last decade or slightly longer, creating software effectively has not just been
about writing the code. It has been (and is) also about better and faster delivery tech‐
nologies. The capabilities of continuous integration/continuous delivery (aka CI/CD),
DevOps, and related practices are now largely taken for granted and easy to achieve.
But historically with GitHub, you still needed to do some amount of integration with
a separate tool to provide a delivery pipeline or other significant automation. While
there have long been ways to bolt on extended CI/CD processes, GitHub has been
missing a truly integrated solution to enable CI/CD and an end-to-end software
development lifecycle (SDLC) within its ecosystem. The answer to that has now
arrived in the form of GitHub Actions.
So how does GitHub Actions achieve this? How does it provide real value on its own
and over other solutions? And, probably most important to you, how do you easily
learn it and start to use it for your own needs?
3
When you’re learning a new technology, it’s important (or at least helpful) to have
some basic context before diving into the technical details. So in this chapter, I’ll
briefly cover some basic information around the following questions:
• What are GitHub Actions?
• What are the use cases for GitHub Actions?
• What are the costs involved?
• When does moving to GitHub Actions make sense?
By the end of this chapter, you’ll have a solid context to frame the rest of your learn‐
ing on GitHub Actions. Now, let’s get started.
Prereqs
This book assumes you already have a basic knowledge of Git and
GitHub. If that’s not the case, there are a number of free resources
to help you understand both.
If you already have a cursory knowledge of GitHub Actions, you
can skip to Chapter 2 to start diving in on more technical details.
But if you’re new to the technology or need to be able to make an
informed decision about whether it makes sense for your project or
team, I recommend reading the material here.
What Is GitHub Actions?
You can define GitHub Actions this way: GitHub Actions is an end-to-end GitHub-
centric SDLC process. It provides an automation platform and framework that has
been missing from GitHub previously and has had to be added on with other solu‐
tions such as Jenkins or Travis CI.
There’s a lot packed into that one statement. But let’s key in on two parts that are at
the heart of the functionality: automation platform and framework.
Automation Platform
For purposes of the end user, GitHub Actions is a way to create and execute automa‐
ted workflows tied to GitHub events. Most commonly, you might think of this in the
context of CI/CD. As an example, you make a change via a pull request, and GitHub
kicks off a continuous delivery pipeline. Prior to GitHub Actions, you would have
needed some external tool or process to respond to a notification from GitHub that
the pull request happened and then to process it. And the automation that happened
after the pull request and initial notification would have been implemented via that
external tool.
4 | Chapter 1: The Basics
With Actions, you now have the means to create this automation within a context
managed by, and within, GitHub. You can define the what, when, and how for auto‐
mated responses to events such as pushes or pull requests. For example, when a push
happens in a branch of your repository, automatically grab the latest code and
attempt to build it. If a pull request happens for a different branch, automatically
build and test the code. If that results in a failure, update a GitHub issue. If there’s not
a failure, automatically proceed with putting out a new release.
Conveniently, you can create and store your automation definitions and workflows
alongside your code in the GitHub repository. And you can edit them there as well. In
short, actions make it easier to automate within GitHub because they are a part of
GitHub. They are based in a GitHub-provided framework that adds structure and
flow. I’ll discuss that next.
Framework
Taking an automation platform from a jumbled collection of mechanisms to an
organized and consumable process requires imposing structure and flow. Without
them, you simply have a collection of tools. With them, you can assemble truly useful
automation to accomplish whatever set of tasks needs to be done.
For Actions, this framework is composed of a core set of related components in Git‐
Hub. These components can be put together to execute simple or complex automa‐
tion in an understandable and predictable way. And this automation is stored in the
repository as code.
I’ll be talking more about these individual components in Chapter 2. But for a quick
overview, it works like this: In response to an occurrence of a matching event, a work‐
flow definition stored within the repository is triggered, which in turn fires off jobs on
designated systems called runners. The jobs are made up of sequences of steps that
either invoke a predefined action or run a command on the runner’s OS shell.
While similar capabilities were available previously in GitHub via mechanisms such
as API calls, they were not as easy to assemble at a higher level. Developers often had
to invest considerable time and effort to learn how to string together the right API
calls and/or integrations with other external tooling (such as Jenkins, Travis CI, etc.).
Or they would use custom scripting and programming to be able to get to the desired
end goal. This was especially true if they wanted to be able to manage processes
through GitHub. (Another workaround was to mirror the repository outside of Git‐
Hub for products to use.)
Actions implements a native framework in GitHub providing a more seamless and
flexible experience. This flexibility is enhanced by the Actions Marketplace, a public
registry where actions can be published and shared. If you want to create workflows
to do common activities (such as checking out code or building with a particular
What Is GitHub Actions? | 5
build tool), you can choose from existing actions in the marketplace. If you want or
need more extensive logic, for which an action doesn’t already exist, you can code
your own custom action using a well-defined structure. Then you can publish and
share it with others via the Marketplace if desired. This approach provides a measure
of flexibility, reusability, and extensibility not previously available with GitHub. A sec‐
ondary benefit is that it can enable rapid prototyping and implementation through
combining actions for various use cases. I’ll talk about those topics in the next sec‐
tion.
Actions versus actions
You may notice that at times the term actions is capitalized and
other times it is not. This is because there is both the larger frame‐
work/platform to talk about and also the smaller, predefined pieces
of functionality. Both of these are referred to with the same term.
Following a recommendation from GitHub, I’ll refer to the larger
platform/framework as GitHub Actions or Actions (uppercase “A”)
and the individual units of functionality as actions (lowercase “a”).
What Are the Use Cases for GitHub Actions?
When CI/CD first came on the scene, dedicated tools such as Jenkins were the pri‐
mary means of creating pipelines. These tools were flexible—arguably, too flexible.
You had to work hard to tie together individual parts into a pipeline. Gradually, with
the widespread adoption of CI/CD, the concept of pipelines has come into its own as a
predefined structure. And so too has the ability to define pipelines that go beyond
just the basics of building simple tests. Today’s CI/CD pipelines can be very complex
and can include advanced testing, multiple integration levels, and automated deploy‐
ments/releases. GitHub Actions allows you to create workflows as complex as needed
to handle these types of operations without ever leaving GitHub’s ecosystem. Further,
it allows you to create as many different workflows as needed for additional automa‐
tion use cases.
While GitHub Actions does not use the term pipeline in its processes, the overall
workflow approach it uses is a similar concept. Workflows chain together smaller
units of work called jobs. Jobs are what you often might see in other applications as
stages, meaning parts of a larger process that perform a distinct and separate function.
In fact, if you’re coming from working with another automation tool, you can think
of the overall GitHub Actions flow as being a pipeline, meaning some change or event
causes a series of automated actions to happen automatically in response.
The main use cases would be in response to something happening in GitHub. But
there are also ways for workflows to be kicked off by events outside of that environ‐
ment, started on a particular schedule, or even initiated manually through the
6 | Chapter 1: The Basics
Actions interface in GitHub. I’ll have more to say about these different ways of initiat‐
ing a workflow in Chapter 2 and also in Chapter 8.
While CI or CI/CD is the primary purpose that comes to mind, workflows and
actions can be used to automate nearly any process. There are two primary places you
can look to get ideas about what actions can be used for: the starter workflows and
the Actions Marketplace.
Workflows versus actions
Just to make sure it’s clear, workflows are the scripts or pipelines
that control the flow and sequence of activity in GitHub Actions.
The individual actions are the functions that can be called to do
targeted tasks from within workflows (like checking out code).
Starter Workflows
To help users bootstrap using Actions, when you start to create a new workflow, Git‐
Hub will present example starter workflows. Figure 1-1 shows an example. You don’t
have to use one of these, but if they suit your purpose or come close to it, you can
click the Configure button and be working on a new workflow very quickly.
As of the time of this writing, the main categories that have starter workflows are:
Deployment
A set of example workflows for creating deployable objects (like containers) and
then deploying them to various cloud platforms
Security
Primarily a set of code-scanning workflows using various security platforms and
their tools
Continuous Integration
A large number of workflows that cover the areas of building, testing, and/or
publishing for a large number of different programming languages and tools
Automation
Some simple examples for basic automation, including a hello world type, one
that demonstrates how to trigger a workflow manually, and a couple that deal
with other GitHub constructs such as pull requests and issues
Pages
Workflows to package/deploy sites using common tools like Gatsby, Astro, Jekyll,
etc.
You can drill into the full list and code for the starter workflows at https://github.com/
actions/starter-workflows.
What Are the Use Cases for GitHub Actions? | 7
Figure 1-1. Starter workflows for use with GitHub Actions
Actions Marketplace
As opposed to workflows that call actions, you can find a useful set of existing actions
to call on the GitHub Marketplace in the Actions section. That’s available at the Git‐
Hub Marketplace. Figure 1-2 shows an example of this area in GitHub.
These are fully functional units that you can select from and use in your own work‐
flows. Think of it as being like the plug-ins or other add-on modules that add func‐
tionality in other applications. As you’ll see in a later chapter, you can get to the
Actions Marketplace from within the GitHub built-in environment for creating a
workflow. You can easily browse and find actions here to save you time and effort
versus having to code your own. (Creating your own actions is covered in
Chapter 11.)
8 | Chapter 1: The Basics
Figure 1-2. GitHub Actions Marketplace
As examples of the kinds of functionality you can find, the Marketplace has featured
categories for interacting with IDEs, working on localization tasks, doing mobile
development, and even working with project management tasks through applications
such as JIRA. The actions on the Marketplace can be from GitHub or from other
sources, such as individuals, organizations, or companies that want to integrate with
Actions.
When you’re creating a new workflow, the Actions Marketplace is a great place to find
existing actions that may already do what you need, thus saving you the effort of cod‐
ing the functionality otherwise. And they’re also free. In fact, you can get started with
GitHub Actions for free. But there are costs associated with certain levels of usage. I’ll
cover more details on that in the next section.
What Are the Use Cases for GitHub Actions? | 9
What Costs Are Involved?
One of the first questions that comes to mind when any individual, team, or organi‐
zation starts thinking about migrating to a new technology is the cost. With GitHub
Actions, you may simply qualify for the free version. But if not, it’s important to have
at least a basic understanding of how the paid model works so you’re not surprised.
The Free Model
GitHub Actions is free if either or both of the following two conditions are true:
• The repositories you use with actions are public.
• The systems you execute the actions on (the runners) are your own (rather than
using the ones provided by GitHub).
That means if you are OK with having your GitHub repositories viewable by every‐
one, or if you can host the systems that will execute the code contained in the steps of
the workflow, you can use the technology for free.
GitHub will not charge you to use self-hosted runners, but you will be required to
install and run the runner application on your own servers. This is needed to allow
GitHub Actions to communicate with your servers to execute your workflows. (Run‐
ners, including the process to create your own, are covered in Chapter 5.)
If the free model doesn’t fit the way you work, you’ll move into the paid model.
The Paid Model
Private repositories are ones with restricted access. Enterprise/corporate GitHub cli‐
ents may frequently use this model, either via restricting access on the public GitHub
site or by using an in-house or on-cloud GitHub instance restricted for their use.
There are two types of items you pay for with GitHub Actions:
• Storage: Actions allow you to store artifacts and packages on GitHub’s resources.
After a certain point, the amount of storage you’re using for artifacts and pack‐
ages will start to cost you.
• Minutes: Actions require processing time on virtual systems.
Artifacts and Packages
Artifacts refer to objects that you upload or generate through your
workflows on GitHub. GitHub Packages are a convenient way to
make things like containers and dependencies accessible.
10 | Chapter 1: The Basics
For a private repository, you start with a certain amount of storage (for artifacts
uploaded during processing of workflows) and minutes on runners that are free.
After those are used up, you may be able to pay for and use more, or you may be cut
off, depending on how you’re paying/billed by GitHub and the defaults for spending
limits you have set up. (Artifacts are discussed in more detail in Chapter 7.)
If you’re paying/billed a regular amount monthly, after you’ve used up the free storage
and minutes, by default, that’s it. You won’t be able to create new artifacts or do addi‐
tional processing.
If, instead, you just get an invoice from GitHub for whatever amount of resources
you’ve used during a billing period and pay that variable amount each time, by
default you can continue to use (and pay for) more minutes and/or storage without
limits.
Default Spending Limits
Default spending limits are referenced in the preceding discussion.
Within GitHub, if you have access and authority to do so, those
default spending limits can be changed through the settings for the
type of account you have (user, organization, or enterprise).
Changing them for an organization or enterprise requires that you
are an owner or billing manager.
For machine usage on a system provided by GitHub, the compute cost is measured in
the minutes you use on the runners. This accumulates as you use more compute but
resets to 0 each month. The amount of storage you use accumulates as you store more
artifacts but is not reset each month. So you just continue to pay the storage cost as
long as you keep the artifacts around on GitHub.
Table 1-1 from GitHub’s documentation shows the breakdown of the free minutes
and free storage you get per month, depending on your account type. This is current
as of the time of this writing and subject to change. Always consult the official docu‐
mentation for the latest pricing information.
Table 1-1. GitHub Actions pricing plans
Plan Storage Minutes (per month)
GitHub Free 500 MB 2,000
GitHub Pro 1 GB 3,000
GitHub Free for Organizations 500 MB 2,000
GitHub Team 2 GB 3,000
GitHub Enterprise Cloud 50 GB 50,000
What Costs Are Involved? | 11
The storage usage is calculated for each month based on hourly usage during the
month.
Usage Rounding
For billing calculations, storage usage is rounded up to the nearest
megabyte, and minute usage is rounded up to the nearest minute.
One other key factor to be aware of is that GitHub Actions charge more for jobs run
on a system provided by GitHub if it requires a Windows or macOS system to exe‐
cute. So, in a paid scenario, your cost to use one of those system versus a Linux sys‐
tem gets scaled up and you pay a premium, as shown in Table 1-2.
Table 1-2. Cost scaling per OS
Operating system Minute multiplier
Linux 1
macOS 10
Windows 2
Table 1-3 shows an example of how the per-minute costs would compare for a pro‐
cess run on different kinds of systems (taken from GitHub’s documentation).
Table 1-3. Per-minute costs across OS
Operating system Per-minute rate (USD)
Linux $0.008
macOS $0.08
Windows $0.016
Current Cost Information
The information in the preceding tables is current as of the time of
this writing and is subject to change. For the latest up-to-date
information on costs around GitHub Actions, refer to the GitHub
documentation.
The price you pay for use is certainly one factor to consider if you’re thinking about
moving to GitHub Actions. But it should not be the only one. In the final section of
this chapter, I’ll discuss how to decide when moving to GitHub Actions makes sense.
12 | Chapter 1: The Basics
When Does Moving to GitHub Actions Make Sense?
Aside from price, what other factors are worth considering for moving to and using
GitHub Actions? Here are a few that may be helpful.
Investment in GitHub
By definition, GitHub Actions are tightly bound to the GitHub ecosystem. They can
only work when run through GitHub’s engine. So anyone needing to work with
Actions will need to be familiar with, and comfortable working with, GitHub as an
interface and environment.
And, if you are using your own runners to execute workflows and actions, you need
to be comfortable with having the runner application installed on your systems.
Use of Public Actions
As discussed previously, GitHub Actions maintains a Marketplace for contributed
actions. As with any public place where you can download components to pull in,
you want to be sure that you are aware of what those actions are doing and that they
meet your security requirements. In short, the responsibility for fit, purpose, and
security when using a public action is yours.
Helpful Security Tips
Chapter 9 in this book covers security. But GitHub also has tips on
securely using actions. See the GitHub documentation for more
details.
Creating Your Own Actions
You have the flexibility to create and use your own actions. There are a couple of dif‐
ferent types, as I discuss in Chapter 11. If you have already invested in creating cus‐
tom functionality another way, you’ll need to learn the action structure and syntax.
Then consider how you would either migrate to more action-based approaches or
have a workflow invoke your existing functionality if feasible to do so. (Chapter 14
discusses approaches for migration.)
Artifact Management
GitHub Actions artifact management is convenient for quick, easy storage and shar‐
ing of artifacts. But it is not a package management system like GitHub Packages or
Artifactory. There is a built-in retention period, after which artifacts are removed. If
this is not suitable for your needs, you’ll need to establish another way to manage
artifacts and connect your workflows to it.
When Does Moving to GitHub Actions Make Sense? | 13
Action Management
GitHub Actions provides a framework for creating and using actions to automate
nearly anything. If you are in a corporate/enterprise environment, you may not want
everyone creating and pulling in actions for shared repositories. Allowing this
without proper controls could open security holes. Controls might take the form of
making sure the set of actions used are approved and manageable. There should also
be a regular update process to ensure any public actions used are kept up to date and
use of them is reviewed as needed.
If employees are creating actions and sharing them for broader use, some sort of code
review and standards should be in place. In short, since actions are written with code
based in GitHub repositories, the same kinds of best practices you would use with
other repositories in GitHub should also apply.
Enforcing Policies for Actions
For information on how to set policies within an enterprise or
organization, see the Enterprise administrator documentation.
In general, the question of how much to invest in, and use, GitHub Actions comes
down to how much you or your organization or enterprise want to gain the benefits
of the new functionality, can migrate any needed existing functionality, and feel com‐
fortable having your code and automation managed in this environment.
Conclusion
In this chapter, I’ve introduced GitHub Actions and shared some basic information
about what the platform is for, its use cases and costs, and factors to consider when
moving to it. GitHub Actions provides a full framework to automate the content you
manage in GitHub. If you are invested in the GitHub ecosystem or considering mov‐
ing to it, workflows and actions provide a good option for implementing automation
such as CI/CD without having to rely on another application. As with any frame‐
work, the automation can be simple or complex. And while the underlying engine is
provided by GitHub, there is an ever-growing community of users providing ready-
made actions and workflows to draw on and lessen the setup/custom investment
required.
Now that the basics of GitHub Actions have been explained, in the next chapter, I’ll
dive in more to help you understand how actions work.
14 | Chapter 1: The Basics
CHAPTER 2
How Does Actions Work?
In Chapter 1, you got acquainted at a high level with the overall framework and value
of GitHub Actions. In this chapter, we’ll dive into the parts that make up GitHub
Actions and how they work together, meaning what kicks them off, what happens
when they run, and so on.
As a reminder, in the world of GitHub Actions, actions can refer to the following:
• The entire system for executing automated workflows in response to events
• The actual units of code and related pieces that implement individual actions
Following the convention suggested by GitHub, the book will use GitHub Actions or
Actions (with an uppercase “A”) to refer to the system and actions (with a lowercase
“a”) to refer to the code units.
To better understand the Actions environment, I’ll provide you with an overview of
how the overall flow works. This includes the types of events that can start the auto‐
mation and a high-level overview of the components that are involved in the execu‐
tion of the automation. Throughout the chapter, I’ll offer some simple example code.
This will give you a solid understanding of how the flow works.
An Overview
At a high level, the GitHub Actions flow is this:
1. Some triggering event happens in a GitHub repository. This event is most often
associated with a unique SHA1 (Secure Hashing Algorithm 1) value and a Git
reference that resolves to an SHA1 value (a ref), such as a branch. But it may also
be an event in GitHub that is not an update to a ref. An example would be a com‐
ment made in a pull request or an issue being updated.
15
2. A dedicated directory in the repository (.github/workflows) is searched for work‐
flow files that are coded to respond to the event type. Many events can also
include additional qualifiers. For example, a workflow can be set up to be trig‐
gered only when a push operation happens on the branch named main.
3. Corresponding workflows are identified, and new runs of the matching work‐
flows are triggered.
The workflow object is the key piece here. A GitHub Actions workflow is a set of code
that defines a sequence and set of steps to execute, similar to a script or a program.
The file itself must be coded in YAML format and stored in the <repository>/.github/
workflows directory.
Workflow files have a specific syntax. A workflow contains one or more jobs. Each job
can be as simple or as complex as needed. Once a workflow is kicked off, the jobs
begin executing. By default, they run in parallel.
Jobs, in turn, are made up of steps. A step either runs a shell command or invokes a
predefined GitHub action. All of the steps in a job are executed on a runner. The run‐
ner is a server (virtual or physical) or a container that has been set up to understand
how to interact with GitHub Actions.
I’ll go into more detail on each of these items later, but Figure 2-1 illustrates the basic
design.
Figure 2-1. Relationship of GitHub Actions components
16 | Chapter 2: How Does Actions Work?
If this seems familiar, it’s probably because it’s a CI pattern. Some change is made that
is automatically detected and that triggers a set of automated processes to run and
respond to the change.
In GitHub Actions, the changes that signal that work needs to be kicked off are trig‐
gering events (aka triggers).
Triggering Workflows
Events trigger workflows. They serve as the signal for work to start happening if a
GitHub Actions workflow is present and the triggering event matches the start condi‐
tions specified in the workflow. An event can be defined in several different ways:
• A person or a process does some operation in a GitHub repository.
• A matching external trigger happens—that is, an event from outside of GitHub.
• A schedule is set up to run a workflow at particular times or intervals.
• A workflow is initiated manually, without an operation having to be done first.
I’ll dive into these different types more in Chapter 3 and extensively in Chapter 8, but
an event triggered from an operation in a GitHub repository is probably the most
common type. An example of this kind of event is a GitHub pull request. If you or a
process initiates a pull request, then a corresponding pull request event is triggered.
There is also a push event for code pushes. In GitHub, there are a large number of
common operations you can do that can serve as triggers for a workflow.
There are also multiple ways to govern when workflows react to the triggers. To
understand this, here’s the first piece of workflow syntax to become familiar with—
the on clause. The on keyword and the lines that follow it define which types of trig‐
gers the workflow will match on and start executing. Some basic types of triggers and
simple examples of the syntax for each follow:
The workflow can respond to a single event such as when a push happens:
on: push
The workflow can respond to a list (multiple events):
on: [push, pull_request]
The workflow can respond to event types with qualifiers, such as branches, tags, or
file paths:
on:
push:
branches:
- main
- 'rel/v*'
Triggering Workflows | 17
tags:
- v1.*
- beta
paths:
- '**.ts'
The workflow can execute on a specific schedule or interval (using standard cron
syntax):
on:
scheduled:
- cron: '30 5,15 * * *'
@interval Syntax
Syntax like @daily, @hourly, and so on is not supported.
The workflow can respond to specific manual events (more about these later):
on: [workflow-dispatch, repository-dispatch]
The workflow can be called from other workflows (referred to as a reuse event):
on: workflow_call
The workflow can respond to webhook events—that is, when a webhook executes and
sends a payload. (See the related documentation for more details on events and pay‐
loads in webhooks.)
The workflow can respond to common activities on GitHub items, such as adding a
comment to a GitHub issue:
on: issue_comment
Events That Trigger Only If the Workflow File Exists
on the Default Branch
Be aware that a subset of less-common events will only trigger a workflow run if the
workflow file (the YAML file in .github/workflows) is on the default branch (usually
main). For those events, if you have the workflow file only on a non-default branch
and you trigger the activity that would normally cause the workflow to run, nothing
will happen.
You can trigger the event from another branch. But, for these special cases, the work‐
flow file has to exist on the default branch, regardless of which branch the trigger
actually happens on. This can present tricky situations when you are trying to develop
a workflow in a different branch and prove it prior to doing a pull request.
18 | Chapter 2: How Does Actions Work?
To see if an event is one that can only be triggered for the default branch in your
repository, go to the documentation and check for a Note section that says, “This
event will only trigger a workflow run if the workflow file is on the default branch.”
Deciding how you want your workflows to be triggered is one of the first steps to
implementing functionality with GitHub Actions. To complete the picture, you need
to understand more about the other parts that make up a workflow. I briefly touched
on these in Chapter 1, but I’ll explain more about them in the next section.
Components
I’m using components here as an umbrella term (not an official one), for the major
pieces that GitHub Actions defines for you to use to build and execute a workflow.
For simplicity, I’ll just do a brief survey of each one to help you understand them
from a higher level.
Steps
Steps are the basic unit of execution you deal with when working with GitHub
Actions. They consist of either invocations of a predefined action or a shell command
to be run on the runner. Any shell commands are executed via a run clause. And any
predefined actions are pulled in via a uses clause. The steps keyword indicates the
start of a series of steps to be run sequentially.
The code listing that follows shows an example of three basic steps from a workflow.
These steps check out a set of code, set up a go environment based on a particular
version, and run the go process on a source file. In the YAML syntax, the - character
indicates where a step starts. The uses clause indicates that this step invokes a prede‐
fined action. The with clause is used to specify arguments/parameters to pass to the
action. And the run clause indicates a command to be run in the shell.
Note that steps can have a name associated with them as well:
steps:
- uses: actions/checkout@v3
- name: setup Go version
uses: actions/setup-go@v2
with:
go-version: '1.14.0'
- run: go run helloworld.go
Components | 19
Runners
Runners are the physical or virtual computers or containers where the code for a
workflow is executed. They can be systems provided and hosted by GitHub (and run
within their control), or they can be instances you set up, host, and control. In either
case, the systems are configured to understand how to interact with the GitHub
Actions framework. This mean they can interact with GitHub to access workflows
and predefined actions, execute steps, and report outcomes.
In a workflow file, runners are defined for jobs simply via the runs-on clause. (Run‐
ners are discussed in more detail in Chapter 5.)
runs-on: ubuntu-latest
Jobs
Jobs aggregate steps and define which runner to execute them on. An individual job is
usually targeted towards accomplishing one particular goal of the overall workflow.
An example could be a workflow that implements a CI/CD pipeline with separate
jobs for building, testing, and packaging.
Aside from the definition of the runner, a job in a workflow is like a function or pro‐
cedure in a programming language. It is made up of a series of individual commands
to run and/or predefined actions to call. This is similar to how a function or proce‐
dure in a programming language is made of individual lines of code and/or calls to
other functions or procedures.
The outcome of the job is surfaced in the GitHub Actions interfaces. Success or fail‐
ure is displayed at the level of the job, not the individual steps. It’s helpful to keep this
success/failure status at the job level in mind when determining how much work you
want any individual job to do. It’s also helpful when considering how much detail you
want to know about success or failure within the workflow execution without having
to drill down.
If you need more granular reports of success or failure displayed at the top level, you
may want to put fewer steps in a job. Or, if you need less-granular indications of
whether a set of steps succeeded or failed, you might put more steps into a job.
Building on the steps and runners previously shown, the next listing shows a simple
job that does the checkout and setup and performs a build:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: setup Go version'
uses: actions/setup-go@v2
20 | Chapter 2: How Does Actions Work?
with:
go-version: '1.14.0'
- run: go run helloworld.go
Workflow
A workflow is like a pipeline. At a high level, it first defines the types of inputs
(events) that it will respond to and under what conditions it will respond to them.
This is what we talked about in the earlier section on events. The response, if the
events and conditions match, is to then execute the series of jobs in the workflow,
which, in turn, execute the steps for each job.
The overall flow is like a continuous integration process in that it responds to a par‐
ticular kind of change and kicks off an automated sequence of work. The next listing
shows an example of a simple workflow for processing Go programs built on the pre‐
vious definitions:
1. name: Simple Go Build
2.
3. on:
4. push:
5. branches:
6. - main
7.
8. jobs:
9. build:
10. runs-on: ubuntu-latest
11. steps:
12. - uses: actions/checkout@v3
13. - name: Setup Go version
14. uses: actions/setup-go@v2
15. with:
16. go-version: '1.15.1'
17. - run: go run hello-world.go
Note that this workflow is written in YAML format. I’ll break down what’s happening
in this file, line by line:
Line 1: The workflow file is assigned a name.
Line 3: This is the on identifier discussed in the section on events.
Lines 4–6: This workflow is triggered when a push operation is done to the branch
main in this GitHub repository.
Line 8: This starts the jobs portion of the workflow.
Line 9: There is one job in this workflow, named build.
Line 10: This job will be executed on a runner system, hosted by GitHub, provisioned
with a standard ubuntu operating system image.
Components | 21
Line 11: This starts the series of steps for this job.
Line 12: The first step is done via pulling in a predefined action. Note the way this is
referenced. actions/checkout@v3 refers to the relative path after github.com, so this
really says it is going to run/use the action defined at github.com/actions/checkout.
Also notice that this is the only line in this step—no parameters need to be passed to
this action because it assumes it is checking out the source from this repository since
it is in this repository.
Line 13: The hyphen at the start of this line indicates this is the start of a second step.
This line is giving the new step a name.
Line 14: The same step is pulling in another predefined action to set up the Go envi‐
ronment.
Lines 15–16: The setup-go action needs a parameter—the version of Go to use. The
parameter is passed as an input to the action via a with clause.
Line 17: This is another step, one that simply runs a command as indicated by the run
keyword. The command is to execute the go run command on an example file in the
repository.
As a reminder, in order to be found, matched to event conditions, and executed auto‐
matically, this code needs to be stored in a YAML file in a special directory in a Git‐
Hub repository: .github/workflows. As an example, you could save the preceding code
in <your repository>/.github/workflows/simple-go-build.yml. (Note the file extension
here needs to be either .yml or .yaml, denoting YAML structure and syntax.)
Workflow Execution
If you push the .github/workflows/simple-go-build.yml file and a corresponding hello-
world.go file to a GitHub repository, you can see the workflow actually run right away.
This is because the event condition set in the workflow (on a push to main) would
match. So the workflow would be triggered and executed as soon as it is pushed.
GitHub repositories contain an Actions selection at the top of the project page. Select‐
ing this puts you into a graphical interface where you can see runs of workflows and
jobs. After pushing the workflow file, if you select the Actions tab at the top, you will
see the execution of your simple workflow, as shown in the example in Figure 2-2.
22 | Chapter 2: How Does Actions Work?
Figure 2-2. Workflow run
From here, you can select a run of a workflow and see the jobs that ran as part of the
workflow and their statuses. Figure 2-3 shows the execution of the job from our sim‐
ple workflow.
Figure 2-3. Run at the job level
Workflow Execution | 23
In later chapters, you’ll see how to use this interface to drill in further to what occurs
when the various steps are executed and how to debug problems, when actions run,
using the interface.
Conclusion
Actions can refer to either the code that implements an action, the automated envi‐
ronment for defining and running those actions as part of a workflow, or both. In this
chapter, I’ve focused on understanding the workflow, its components, and the way it
is executed.
Workflows are like software pipelines. They can be initiated when a triggering event
occurs (like continuous integration), and they aggregate one or more jobs to accom‐
plish their overall task. Each job in turn aggregates one or more steps to do smaller
units of work. The execution of the steps in a single job results in a success/failure
outcome for the job, which feeds back into success/failure for the overall workflow.
Each job declares what kind of runner system (operating system and version) it will
run in. And, at the lowest level, steps can invoke predefined GitHub Actions or run
simple commands on that system.
Now that you have a basic understanding of how workflows work within GitHub
Actions, Chapter 3 will give you a similar understanding of how individual actions
work.
24 | Chapter 2: How Does Actions Work?
CHAPTER 3
What’s in an action?
In Chapter 2, we explored how GitHub Actions does its processing. The core func‐
tionality centers around workflows—the code that runs in response to an event and
executes jobs to do some work. At the lowest level in your workflow, the workflow’s
jobs execute steps. And steps can call either an OS command or an implementation of
separate functionality that GitHub Actions simply refers to as an action.
Workflows versus actions
Since the distinction between actions and workflows can be one of
the points that remains confusing for a while, here’s a reminder to
think of actions as being like plug-ins or modules in other applica‐
tions and the workflows as being more like the pipelines or scripts
that use those modules or plug-ins.
You have the background now to understand where the implementation of an actual
action is used—when a step in a workflow calls it. In this chapter, I’ll continue the
broad overview of the GitHub Actions platform by looking at what makes up an indi‐
vidual action. Specifically, I’ll discuss the following:
• The structure of an action
• Interfacing with actions
• Using actions
• Public actions and the Actions Marketplace
25
Implementation of an action
Note that this chapter does not describe how to create a new action.
Chapter 11 goes into detail on how to create your own custom
action.
The Structure of an action
The implementation of an action can range from very simple to very complex. On the
simple side, it might be a small shell script that gets executed. On the complex end, it
may be a large set of implementation code, test cases, and workflows to handle CI/CD
tasks like validating content, building, checking for vulnerabilities, packaging,
and so on.
The checkout action referenced in Chapter 2 is one such implementation on the com‐
plex end of that range. Figure 3-1 shows part of the main page for the GitHub reposi‐
tory behind that action.
Figure 3-1. Checkout action in GitHub
26 | Chapter 3: What’s in an action?
Underlying each action is a code base in a GitHub repository. Like many other
projects in GitHub, this repository has a lot of supporting pieces in addition to the
code (licensing, tests, source, .gitattributes, etc.) If you drill into the src area, you can
see more of the underlying implementation, including the TypeScript files (.ts exten‐
sion) that do the real work. Figure 3-2 shows the contents of the src subdirectory.
Figure 3-2. src directory in checkout action
On the main page, you can also see references to the contributors, the README file,
and other typical information such as the language breakdown and the usage infor‐
mation. (Note that, as a testament to the use of actions, the checkout action has
nearly 4 million used by references, as shown in Figure 3-3.)
The Structure of an action | 27
Figure 3-3. Additional info on action page
This action also has a supporting set of workflow files. Like any other workflows,
these are stored in the .github/workflows subdirectory of the repository. In the case of
the checkout action, the files help to validate content being updated in the repository.
They are set up to respond to events such as pushes and pull requests. The set of
workflows associated with this action is shown in Figure 3-4.
So workflows use actions to do work in steps, and actions use workflows for CI/CD,
automation, validation, etc. From this, you can start to see how the parts of GitHub
Actions can work together at a broader level.
The key part of a project in GitHub that allows it to be used as an action is a special
file that designates it as an action. This file also describes the action’s key characteris‐
tics, such as the inputs it can have. I’ll discuss this file in the next section.
28 | Chapter 3: What’s in an action?
Random documents with unrelated
content Scribd suggests to you:
course I am glad that the man is not badly hurt. Still, a few shot in
the arm will hardly keep him in bounds. His legs were intended,” she
laughed lightly. “What miserable aim Tompkins must take.”
“He's a bit off in his physiology, my dear,” said Cecil, with a
nervous attempt at humour. He did not like the expression in his
sister's face. Somehow, he was ashamed.
“Oh, it's bad enough,” said Penelope. “It was his left arm—the
upper arm, too. I think the aim was rather good.”
“Pray, how do you know all of this, Penelope?” asked her ladyship,
lifting her eyebrows. “I 've heard that you see Mr. Shaw occasionally,
but you can't be his physician, I'm sure.”
Penelope flushed to the roots of her hair, but suppressed the
retort which would have been in keeping with the provocation.
“Oh, dear, no!” she replied. “I'm too soft-hearted to be a
physician. I saw Mr. Shaw just after the—ah—the incident.”
“You shaw Saw—I mean you saw Shaw?” gasped Bazelhurst.
“She sees him frequently, Cecil. It was not at all unusual that she
should have seen him to-day. I daresay he waited to show you his
wound before going to a surgeon.”
Penelope could not resist the temptation to invent a story befitting
the moment. Assuming a look of concern, she turned to her brother
and said: “He is coming to see you about it to-morrow, and he is
coming armed to the teeth, attended by a large party of friends. Mr.
Shaw says he will have satisfaction for the death of that dog if he
has to shoot everybody on the place.”
“Good Lord!” cried the duke. There was instant excitement. “I
believe the wretch will do it, too.”
“Oh, I say, Bazelhurst, settle with him for the dog,” said De Peyton
nervously. He looked at his watch and then at his wife. The entire
party now was listening to the principal speakers.
“Nonsense!” exclaimed Lady Evelyn. “He won't come. It's all
bluster. Don't let it frighten you, Cecil. I know the manner of man.”
“I wish you could have seen him this morning,” murmured
Penelope, thoroughly enjoying the unexpected situation. Her
conscience was not troubled by the prevarication.
“By Jove, I think it would be wise to send over and find out what
he valued the brute at,” said Cecil, mopping his brow.
“Good. We'll send Penelope to act as ambassador,” said her
ladyship. “She seems to be on friendly terms with the enemy.”
“To act as ambassador from Cowardice Court?” questioned
Penelope, loftily, yet with cutting significance. “No, I thank you. I
decline the honour. Besides,” with a reflective frown, “I don't believe
it is diplomacy he's after.”
“I say what the deuce do you suppose the confounded savage has
in mind?” exclaimed the duke. “I 'Ve heard of the way these
cowboys settle their affairs. You don't imagine—” and he paused
significantly.
“It looks like it's going to be a da—rather disagreeable affair,” said
De Peyton sourly.
“Good heavens, what are we to do if he comes here with a lot of
desperadoes and begins to shoot?” cried Mrs. Odwell, genuinely
alarmed. “I've read so much of these awful mountain feuds.”
“Don't be alarmed. Lord Bazelhurst will attend to the gentleman,”
said Lady Evelyn blandly. His lordship's monocle clattered down and
the ice rattled sharply in his glass. “To—to be sure,” he agreed.
“Don't be in the least worried. I 'll attend to the upstart. What time's
he coming, Pen?” A door banged noisily near by, and every one
jumped as though a gun had been fired. While the “ohs” were still
struggling from their lips, Hodder, the butler, came into the room,
doing his best to retain his composure under what seemed to be
trying circumstances. “What is it, Hodder?” demanded her ladyship.
“The cook, your ladyship. She's fallen downstairs and broken her
leg,” announced Hodder. He did not betray it, but he must have been
tremendously surprised by the sigh of relief that went up on all
sides. Lord Bazelhurst went so far as to laugh.
“Ha, ha! is that all?”
“Oh, dear, I'm so glad!” cried Miss Folsom, impulsively. “I was
frightened half to death. It might have been Mr.—”
“Don't be silly, Rose,” said Lady Bazelhurst. “Where is she,
Hodder?”
“In the laundry, your ladyship. There are two fractures.”
“By Jove, two legs instead of one, then—worse than I thought,”
cried Bazelhurst, draining his glass.
“Send at once for a doctor, Hodder, and take her to her room. Is
n't it annoying,” said her ladyship. “It's so difficult to keep a cook in
the mountains.”
“Don't see how she can get away without legs,” observed De
Peyton.
“I'll come with you, Hodder. Perhaps I can do something for her,”
said Penelope, following the butler from the room.
“Don't take too many patients on your hands, my dear,” called the
mistress, with a shrill laugh.
“Yes; remember to-morrow,” added the duke. Then, suddenly: “I
believe I'll lend a hand.” He hurried after Penelope, rather actively
for him.
Lord Bazelhurst visited his wife's room later in the night, called
there by a more or les: peremptory summons. Cecil had been taking
time by the forelock in anticipation of Shaw's descent in the morning
and was inclined to jocundity.
“Cecil, what do you think of Penelope's attitude toward Mr. Shaw?”
she asked, turning away from the window which looked out over the
night in the direction of Shaw's place.
“I didn't know she had an attitude,” replied he, trying to focus his
wavering gaze upon her.
“She meets him clandestinely and she supports him openly. Is n't
that an attitude, or are you too drunk to see it?”
“My dear, remember you are speaking of my sister,” he said with
fine dignity but little discrimination. “Besides, I am not too drunk. I
do see it. It's a demmed annoying attitude. She 's a traitor, un'stand
me? A traito-tor. I intend to speak to her about it.”
“It is better that you should do it,” said his wife. “I am afraid I
could not control my temper.”
“Penelope's a disgrace—a nabsolute disgrace; now many legs did
Hodder say—”
“Oh, you're disgusting!” cried Lady Evelyn. “Go to bed! I thought I
could talk to you to-night, but I can't. You scarcely can stand up.”
“Now, Evelyn, you do me injustice. I'm only holding to this chair to
keep it from moving 'round the room. See that? Course I c'n stan'
up,” he cried, triumphantly.
“I am utterly disgusted with you. Oh, for a man! A man with real
blood in his veins, a man who could do something besides eat and
drink at my cost. I pay your debts, clothe you, feed you—house your
ungrateful sister—and what do I get in return? This!”
Lord Bazelhurst's eyes steadied beneath this unexpected assault,
his legs stiffened, his shoulders squared themselves in a pitiful
attempt at dignity.
“Lady Bazelhurst, you—you—” and then he collapsed into the
chair, bursting into maudlin tears. She stood over by the dressing-
table and looked pitilessly upon the weak creature whose
hiccoughing sobs filled the room. Her colour was high, her breathing
heavy. In some way it seemed as though there was so much more
she could have said had the circumstances been different.
There came a knock at the door, but she did not respond. Then
the door opened quietly and Penelope entered the room, resolutely,
fearlessly. Evelyn turned her eyes upon the intruder and stared for a
moment.
“Did you knock?” she asked at last.
“Yes. You did not answer.”
“Was n't that sufficient?”
“Not to-night, Evelyn. I came to have it out with you and Cecil.
Where is he?”
“There!”
“Asleep?” with a look of amazement.
“I hope not. I should dislike having to call the servants to carry
him to his see. Poor old chap!” She went over and shook him by the
shoulder. He sat up and stared at her blankly through his drenched
eyes. Then, as if the occasion called for a supreme effort, he tried to
rise, ashamed that his sister should have found him in his present
condition. “Don't get up, Cecil. Wait a bit and I'll go to your—”
“What have you to say to me, Penelope,” demanded Evelyn, a
green light in her eyes.
“It can wait. I prefer to have Cecil—understand,” she said, bitterly.
“If it 's about our affair with Shaw, it won't make any difference
whether Cecil understands or not. Has your friend asked you to
plead for him? Does he expect me to take him up on your account
and have him here?”
“I was jesting when I said he would come to-morrow,” said
Penelope, ignoring the thrust and hurrying to her subject. “I could
n't go to sleep to-night if I neglected to tell you what I think of the
outrage this morning. You and Cecil had no right to order Tompkins
to shoot at Mr. Shaw. He is not a trespasser. Some one killed his dog
to-day. When he pursued the coward, a second shot was fired at
him. He was wounded. Do you call that fair fighting? Ambushed,
shot from behind a tree. I don't care what you and Cecil think about
it, I consider it despicable. Thank God, Cecil was not really to blame.
It is about the only thing I can say to my brother's credit.”
Lady Bazelhurst was staring at her young sister-in-law with wide
eyes. It was the first time in all her petted, vain life that any one had
called her to account. She was, at first, too deeply amazed to resent
the sharp attack.
“Penelope Drake!” was all she could say. Then the fury in her soul
began to search for an outlet. “How dare you? How dare you?”
“I don't mean to hurt you, I am only telling you that your way of
treating this affair is a mistake. It can be rectified. You don't want to
be lawless; you don't understand what a narrow escape from murder
you have had. Evelyn, you owe reparation to Mr. Shaw. He is—”
“I understand why you take his side. You cheapen and degrade
yourself and you bring shame upon your brother and me by your
disgraceful affair with this ruffian. Don't look shocked! You meet him
secretly, I know—how much farther you have gone with him I don't
know. It is enough that you—”
“Stop! You shall not say such things to me!”
“You came in here to have it out with me. Weil, we'll have it out.
You think because you're English, and all that, that you are better
than I. You show it in your every action; you turn up your nose at
me because I am an American. Well, what if I am? Where would you
be if it were not for me? And where would he be? You'd starve if it
were not for me. You hang to me like a leech—you sponge on me,
you gorge yourself—”
“That is enough, Evelyn. You have said all that is necessary. I
deserve it, too, for meddling in your affairs. It may satisfy you to
know that I have always despised you. Having confessed, I can only
add that we cannot live another hour under the same roof. You need
not order me to go. I shall do so of my own accord—gladly.”
Penelope turned to the door. She was as cold as ice.
“It is the first time you have ever done anything to please me. You
may go in the morning.”
“I shall go to-night!”
“As you like. It is near morning. Where do you expect to go at this
hour of night?”
“I am not afraid of the night. Tomorrow I shall send over from the
village for my trunks.” She paused near the door and then came
back to Cecil's side. “Goodbye, Cecil. I'll write. Good-bye.” He looked
up with a hazy smile.
“G'night,” he muttered thickly.
Without another word or so much as a glance at Lady Bazelhurst,
Penelope Drake went swiftly from the room. The big hall clock struck
the half-hour after eleven. Some one—a woman—was laughing in
the billiard-room below; the click of the balls came to her ears like
the snapping of angry teeth. She did not hesitate; it was not in her
nature. The room in which she had found so much delight was now
loathsome to her. With nervous fingers she threw the small things
she most cherished into a bag,—her purse, her jewels, her little
treasures. Somehow it seemed to her as if she were hurrying to
catch a night train, that was all. With her own strong young arms
she dragged the two huge trunks from the closet. Half an hour later
they were full and locked. Then she looked about with a dry,
mirthless smile.
“I wonder where I am to go?” she murmured, half aloud. A
momentary feeling of indecision attacked her. The click of the balls
had ceased, the clock had struck twelve. It was dark and still, and
the wind was crying in the trees.
“She won't go,” Lady Bazelhurst was saying to herself, as she sat,
narrow-eyed and hateful, in her window looking out into the night.
“Life is too easy here.” The light from the porch lanterns cast a
feeble glow out beyond the porte-cochère and down the drive. As
she stared across the circle, the figure of a woman suddenly cut a
diametric line through it, and lost itself in the wall of blackness that
formed the circumference. Lady Evelyn started and stared
unbelievingly into the darkness, striving to penetrate it with her
gaze. “It was she—Penelope,” she cried, coming to her feet. “She's
really gone—she meant it.” For many minutes she peered out into
the night, expecting to see the shadow returning. A touch of anxious
hope possessing her, she left the window and hurried down the
corridor to Penelope's room. What she found there was most
convincing. It was not a trick of the lanterns. The shadow had been
real. It must be confessed that the peevish heart of Lady Bazelhurst
beat rather rapidly as she hastened back to the window to peer
anxiously out into the sombre park with its hooting owls and
chattering night-bugs. The mournful yelp of a distant dog floated
across the black valley. The watcher shuddered as she recalled
stories of panthers that had infested the great hills. A small feeling
of shame and regret began to develop with annoying insistence.
An hour dragged itself by before she arose petulantly, half
terrified, half annoyed in spite of herself. Her husband still was
sitting in the big chair, his face in his hands. His small, dejected
figure appealed to her pity for the first time in the two years of their
association. She realized what her temper had compelled her to say
to him and to his sister; she saw the insults that at least one of them
had come to resent.
“I hope that foolish girl will come back,” she found herself saying,
with a troubled look from the window. “Where can the poor thing
go? What will become of her? What will everyone say when this
becomes known?” she cried, with fresh selfishness. “I—I should not
have let her go like this.”
Even as she reproached herself, a light broke in upon her
understanding; a thought whirled into her brain and a moment later
she knew where she could go! “How simple I am. Shaw will welcome
her gladly. She's with him by this time—his doors have opened to
her. The little wretch! And I've been trying so hard to pity her!” She
laughed again so shrilly that his lordship stirred and then looked up
at her stupefied, uncertain.
“Hullo,” he grunted. “What time is it?”
“Oh, you're awake, are you?” scornfully.
“Certainly. Have I been dozing? What's there to laugh at, my
dear?” he mumbled, arising very unsteadily. “Where's Pen?”
“She's gone. She's left the house,” she said, recurring dread and
anxiety in her voice. A glance at the darkness outside brought back
the growing shudders.
“What—what d' ye mean?” demanded he, bracing up with a
splendid effort.
“She's left the house, that's all. We quarrelled. I don't know where
she's gone. Yes, I do know. She's gone to Shaw's for the night. She's
with him. I saw her going,” she cried, striving between fear and
anger.
“You 've—you've turned her out? Good Lord, why—why did you let
her go?” He turned and rushed toward the door, tears springing to
his eyes. He was sobering now and the tears were wrenched from
his hurt pride. “How long ago?”
“An hour or more. She went of her own accord. You'll find her at
Shaw's,” said her ladyship harshly. She hated to admit that she was
to blame. But as her husband left the room, banging the door after
him, she caught her breath several times in a futile effort to stay the
sobs, and then broke down and cried, a very much abused young
woman. She hated everybody and everything.
L
CHAPTER V—IN WHICH DAN CUPID
TRESPASSES
ADY BAZELHURST was right. Penelope was making her way
through the blackest of nights toward the home of Randolph
Shaw. In deciding upon this step, after long deliberation, she
had said to herself: “Randolph Shaw is the only real man I 've seen
since coming to the mountains. I can trust him to help me to-night.”
It was fully three miles to Shaw's place, most of the way over the
narrow valley road. She knew she would encounter but few tortuous
places. The last half-mile, however, was steep, rugged, and
unfamiliar to her. She had ventured no nearer to his home than
Renwood's deserted cottage, lying above and to the south of the
road, almost at the base of the long hill on whose side Shaw had
built his big home. To climb that hill was no easy task in daylight; at
midnight, with the stars obscured by clouds and tree-tops, there was
something perilously uncertain in the prospect.
Only the knowledge that patience and courage eventually would
bring her to the end made the journey possible. Time would lead her
to the haven; care would make the road a friend; a stout heart was
her best ally. Strength of limb and strength of purpose she had, in
use and in reserve. No power could have made her turn back
willingly. Her anxious eyes were set ahead in the blackness; her
runaway feet were eager in obedience to her will.
“Why couldn't I have put it off until morning?” she was saying to
herself as she passed down the gravelled drive and advanced to
meet the wall of trees that frowned blackly in her face. “What will he
think? What will he say? Oh, he'll think I'm such a silly, romantic
fool. No, he won't. He'll understand. He'll help me on to Platts-burg
to-morrow. But will he think I've done this for effect? Won't he think
I'm actually throwing myself at his head? No, I can't turn back. I'd
rather die than go back to that house. It won't matter what he
thinks; I'll be away from all of it tomorrow. I'll be out of his life and I
won't care what he thinks. England! Goodness, what's that?” She
had turned a bend in the drive and just ahead there was a light. A
sigh of relief followed the question. It came from the lantern which
hung to a stake in the road where the new stone gate-posts were
being built by workmen from town. Bazelhurst Villa was a quarter of
a mile, through the park, behind her; the forest was ahead.
At the gate she stopped between the half-finished stone posts and
looked ahead with the first shiver of dismay. Her limbs seemed ready
to collapse. The flush of anger and excitement left her face; a white,
desolate look came in its stead. Her eyes grew wide and she blinked
her lashes with an awed uncertainty that boded ill for the stability of
her adventure. An owl hooted in mournful cadence close by and she
felt that her hair was going straight on end. The tense fingers of one
hand gripped the handle of the travelling-bag while the other went
spasmodically to her heart.
“Oh!” she gasped, moving over quickly to the stake on which the
lantern hung. The wind was rushing through the tree-tops with
increased fervour; the air was cool and wet with the signs of rain; a
swirl of dust flew up into her face; the swish of leaves sounded like
the splashing of water in the air. Holding her heart for minutes, she
at last regained some of the lost composure. A hysterical laugh fell
from her lips. “What a goose! It was an owl and I've heard hundreds
of them up here. Still, they do sound different outside of one's own
room. It's going to rain. What wretched luck! Dear me, I can't stand
here all night. How black it is ahead there. Oooh! Really, now, it
does seem a bit terrifying. If I only had a lantern it would n't be so
—” her gaze fell upon the labourers' lantern that clattered aimlessly,
uselessly against the stake. An instant later she had jerked it from its
fastenings with a cry of joy. “I'll send it back when they go for my
trunks. What luck!”
Without a second's hesitation she started off briskly into the
woodland road, striding along with the splendid swing of the healthy
Englishwoman who has not been trained to dawdle. Her walking-
skirt gave free play to her limbs; she was far past the well-known
“line in the road” before she paused to take a full breath and to
recapitulate.
Her heart beat faster and the sudden glow in her cheek was not
from the exercise. Somehow, out there alone in the world, the most
amazing feeling of tenderness sped on ahead to Randolph Shaw.
She tried to put it from her, but it grew and grew. Then she blushed
deep within herself and her eyes grew sweet with the memory of
those stolen, reprehensible hours along the frontier. Something
within her breast cried out for those shining, gone-by moments,
something seemed to close down on her throat, something flooded
her eyes with a softness that rolled up from her entire being. Their
line! Their insurmountable barrier! An absurd yet ineffable longing to
fall down and kiss that line came over her with compelling force.
Her head grew light with the thought of those moments when
their horses stood with muzzles together as if kissing by proxy—the
flush grew deeper, though her blood went cold and she trembled.
A pitiful confusion seized her, an inexplicable timidity crept into her
heart, replacing the bold assurance that had been recklessly carrying
her on to him. It was as though some one had whispered the truth
into her ear and she was beginning to believe.
From that moment her courage began to fail. The glow from her
lantern was a menace instead of a help. A sweet timorousness
enveloped her and something tingled—she knew not what.
Spattering raindrops whizzed in her face, ominous forerunners
from the inky sky. The wind was whistling with shrill glee in the tree-
tops and the tree-tops tried to flee before it. A mile and a half lay
between her and the big cottage on the hillside—the most arduous
part of the journey by far. She walked and ran as though pursued,
scudding over the road with a swiftness that would have amazed
another, but which seemed the essence of slowness to her. Thoughts
of robbers, tramps, wild beasts, assailed her with intermittent
terrors, but all served to diminish the feeling of shyness that had
been interfering with her determination.
Past Renwood's cottage she sped, shuddering as she recognized
the stone steps and path that ran up the hillside to the haunted
house. Ghosts, witches, hobgoblins fell into the procession of
pursuers, cheered on by the shrieking wind that grew more noisome
as her feet carried her higher up the mountain. Now she was on new
ground. She had never before explored so far as this. The hill was
steep and the road had black abysses out beyond its edges....
She was breathless, half dead from fatigue and terror when at last
her feet stumbled up the broad steps leading to his porch.
Trembling, she sank into the rustic bench that stood against the
wall. The lantern clattered to her feet, and the bag with her jewels,
her letter of credit, and her curling irons slid to the floor behind the
bench. Here was his home! What cared she for the storm?
Even as she lay there gasping for breath, her eyes on the shadowy
moon that was breaking its way through the clouds, three men
raced from the stables at Bazelhurst Villa bent on finding the mad
young person who had fled the place. Scarcely knowing what
direction he took, Lord Bazelhurst led the way, followed by the duke
and the count, all of them supplied with carriage lamps, which, at
any other time, would have been sickening in their obtrusiveness.
Except for Lady Evelyn, the rest of the house slept the sleep of ease.
Gradually Penelope recovered from the effects of the mad race up
the hill. The sputtering flame in the lantern called her into action.
Clutching it from the floor of the porch, she softly began a tour of
inspection, first looking at her watch to find that it was the unholy
hour of two! Had some one yelled boo! she would have swooned, so
tense was every nerve. Now that she was here, what was she to do?
Her heart came to her mouth, her hand shook, but not with fear; a
nervous smile tried to wreak disaster to the concern in her eyes.
The house was dark and still. No one was stirring. The porch was
littered with rugs and cushions, while on a small table near the end
stood a decanter, a siphon, and two glasses. Two? He had said he
was alone except for the housekeeper and the servants. A visitor,
then. This was not what she had expected. Her heart sank. It would
be hard to face the master of the house, but—a stranger? Cigarette
stubs met her bewildered, troubled gaze—many of them. Deduction
was easy out there in the lonely night. It was easy to see that Shaw
and his companion sat up so late that the servants had gone to bed.
Distractedly she looked about for means of shelter on the porch
until daylight could abet her in the flight to the village beyond.
The storm was sure to come at no far distant time. She knew and
feared the violence of the mountain rains.
“By all that's holy,” came in a man's voice, low-toned and
uncertain; “it is a dream, after all!”
She turned like a flash, with a startled exclamation and an
instinctive movement as if to shield herself from unbidden gaze. Her
lips parted and her heart pounded like a hammer. Standing in the
doorway was Randolph Shaw, his figure looming up like monstrous,
wavering genie in the uncertain light from the shaking lantern. His
right hand was to his brow and his eyes were wide with incredulous
joy. She noticed that the left sleeve of his dinner jacket hung limp,
and that the arm was in a white sling beneath.
“Is it really you?” he cried, his hand going instinctively to his
watch-pocket as if doubting that it was night instead of morning.
“I've—I 've run away from them,” she stammered. “It's two o'clock
—don't look! Oh, I'm so sorry now—why did I—”
“You ran away?” he exclaimed, coming toward her. “Oh, it can't be
a dream. You are there, aren't you?” She was a pitiable object as
she stood there, powerless to retreat, shaking like a leaf. He took
her by the shoulder. “Yes—it is. Good Lord, what does it mean? What
has happened? How did you come here? Are you alone?”
“Utterly, miserably alone. Oh, Mr. Shaw!” she cried despairingly.
“You will understand, won't you?”
“Never! Never as long as I live. It is beyond comprehension. The
wonderful part of it all is that I was sitting in there dreaming of you
—yes, I was. I heard some one out here, investigated and found you
—you, of all people in the world. And I was dreaming that I held you
in my arms. Yes, I was! I was dreaming it—”
“Mr. Shaw! You should n't—”
“And I awoke to find you—not in my arms, not in Bazelhurst Villa,
but here—here on my porch.”
“Like a thief in the night,” she murmured. “What do you think of
me?”
“Shall I tell you—really?” he cried. The light in his eyes drove her
back a step or two, panic in her heart.
“N—no, no—not now!” she gasped, but a great wave of exaltation
swept through her being. He turned and walked away, too dazed to
speak. Without knowing it, she followed with hesitating steps. At the
edge of the porch he paused and looked into the darkness.
“By Jove, I must be dreaming,” she heard him mutter.
“No, you are not,” she declared desperately. “I am here. I ask your
protection for the night. I am going away—to England—to-morrow. I
could n't stay there—I just could n't. I'm sorry I came here—I'm—”
“Thank heaven, you did come,” he exclaimed, turning to her
joyously. “You are like a fairy—the fairy princess come true. It's
unbelievable! But—but what was it you said about England?” he
concluded, suddenly sober.
“I am go—going home. There's no place else. I can't live with her,”
she said, a bit tremulously.
“To England? At once? Your father—will he—?”
“My father? I have no father. Oh!” with a sudden start Her eyes
met his in a helpless stare. “I never thought. My home was at
Bazelhurst Castle—their home. I can't go there. Good heavens, what
am I to do?”
A long time afterward she recalled his exultant exclamation,
checked at its outset,—recalled it with a perfect sense of
understanding. With rare good taste he subdued whatever it was
that might have struggled for expression and simply extended his
right hand to relieve her of the lantern.
“We never have been enemies, Miss Drake,” he said, controlling
his voice admirably. “But had we been so up to this very instant, I
am sure I 'd surrender now. I don't know what has happened at the
Villa. It does n't matter. You are here to ask my protection and my
help. I am at your service, my home is yours, my right hand also.
You are tired and wet and—nervous. Won't you come inside? I 'll get
a light in a jiffy and Mrs. Ulrich, my housekeeper, shall be with you
as soon as I can rout her out. Come in, please.” She held back
doubtfully, a troubled, uncertain look in her eyes.
“You will understand, won't you?” she asked simply.
“And no questions asked,” he said from the doorway. Still she held
back, her gaze going involuntarily to the glasses on the table. He
interpreted the look of inquiry. “There were two of us. The doctor
was here picking out the shot, that 's all. He 's gone. It's all right.
Wait here and I'll get a light.” The flame in her lantern suddenly
ended its feeble life.
She stood inside his doorway and heard him shuffle across the
floor in search of the lamps.
“Dark as Egypt, eh?” he called out from the opposite side of the
room.
“Not as dark as the forest, Mr. Shaw.”
“Good heavens, what a time you must have had. All alone, were
you?”
“Of course. I was not eloping.”
“I beg your pardon.”
“Where were you sitting when I came up?”
“Here—in the dark. I was waiting for the storm to come and dozed
away, I daresay. I love a storm, don't you?”
“Yes, if I 'm indoors. Ah!” He had struck a match and was lighting
the wick of a lamp beside the huge fireplace. “I suppose you think I
'm perfectly crazy. I 'm horrid.”
“Not at all. Sit down here on the couch, please. More cheerful, eh?
Good Lord, listen to the wind. You got here just in time. Now, if
you'll excuse me, I'll have Mrs. Ulrich down in a minute. She'll take
good care of you. And I 'll make you a nice hot drink, too. You need
it.” In the door of the big living-room he turned to her, a look of
extreme doubt in his eyes. “By Jove, I bet I do wake up. It can't be
true.” She laughed plaintively and shook her head in humble self-
abasement. “Don't be lonesome. I'll be back in a minute.”
“Don't hurry,” she murmured apologetically. Then she settled back
limply in the wide couch and inspected the room, his footsteps
noisily clattering down the long hallway to the left. She saw, with
some misgiving, that it was purely a man's habitation. Shaw
doubtless had built and furnished the big cottage without woman as
a consideration. The room was large, comfortable, solid; there was
not a suggestion of femininity in, it—high or low—except the general
air of cleanliness. The furniture was rough-hewn and built for use,
not ornamentation; the walls were hung with English prints, antlers,
mementoes of the hunt and the field of sport; the floor was covered
with skins and great “carpet rag” rugs. The whole aspect was so
distinctly mannish that her heart fluttered ridiculously in its
loneliness. Her cogitations were running seriously toward riot when
he came hurriedly down the hall and into her presence.
“She'll be down presently. In fact, so will the cook and the
housemaid. Gad, Miss Drake, they were so afraid of the storm that
all of them piled into Mrs. Ulrich's room. I wonder at your courage in
facing the symptoms outdoors. Now, I'll fix you a drink. Take off
your hat—be comfortable. Cigarette? Good! Here's my sideboard.
See? It's a nuisance, this having only one arm in commission; affects
my style as a barkeep. Don't stir; I'll be able—”
“Let me help you. I mean, please don't go to so much trouble.
Really I want nothing but a place to sleep to-night. This couch will
do—honestly. And some one to call me at daybreak, so that I may
be on my way.” He looked at her and laughed quizzically. “Oh, I'm in
earnest, Mr. Shaw, I would not have stopped here if it had n't been
tor the storm.”
“Come, now, Miss Drake, you spoil the fairy tale. You did intend to
come here. It was the only place for you to go—and I'm glad of it.
My only regret is that the house is n't filled with chaperons.”
“Why?” she demanded with a guilty start.
“Because I could then say to you all the things that are in my
heart—aye, that are almost bursting from my lips. I—I can't say
them now, you know,” he said, and she understood his delicacy. For
some minutes she sat in silence watching him as he clumsily mixed
the drinks and put the water over the alcohol blaze. Suddenly he
turned to her with something like alarm in his voice. “By George, you
don't suppose they 'll pursue you?”
“Oh, would n't that be jolly? It would be like the real story-book—
the fairy and the ogres and all that. But,” dubiously, “I'm sorely
afraid they consider me rubbish. Still—” looking up encouragingly
—“my brother would try to find me if he—if he knew that I was
gone.”
To her surprise, he whistled softly and permitted a frown of
anxiety to creep over his face. “I had n't thought of that,” he
observed reflectively. Then he seemed to throw off the momentary
symptoms of uneasiness, adding, with a laugh: “I daresay nothing
will happen. The storm would put a stop to all idea of pursuit.”
“Let them pursue,” she said, a stubborn light in her eyes. “I am
my own mistress, Mr. Shaw. They can't take me, willy nilly, as if I
were a child, you know.”
“That's quite true. You don't understand,” he said slowly, his back
to her.
“You mean the law? Is it different from ours?”
“Not that. The—er—situation. You see, they might think it a trifle
odd if they found you here—with me. Don't you understand?” He
turned to her with a very serious expression. She started and sat
bolt upright to stare at him comprehensively.
“You mean—it—it isn't quite—er—”
“Regular, perhaps,” he supplied. “Please keep your seat! I'm not
the censor; I'm not even an opinion. Believe me, Miss Drake, my
only thought was and is for your good.”
“I see. They would believe evil of me if they knew I had come to
you,” she mused, turning quite cold.
“I know the kind of people your sister-in-law has at her place, Miss
Drake. Their sort can see but one motive in anything. You know
them, too, I daresay.”
“Yes, I know them,” she said uneasily. “Good heavens, what a fool
I've been,” she added, starting to her feet. “I might have known they
'll say all sorts of terrible things. They must not find me here. Mr.
Shaw, I'm—I am so ashamed—I wonder what you are thinking of
me.” Her lip trembled and there was such a pleading look in her dark
eyes that he controlled himself with difficulty. It was only by
imposing the severest restraint upon his susceptibilities that he was
able to approach her calmly.
“I can't tell you now—not here—what I am thinking. It is n't the
place. Maybe—maybe you can read my thought. Please—Miss Drake.
Look up, please. Can't you read—oh, there now—I beg your pardon!
You come to me for protection and I—well, don't be too hard on me
just yet. I'll find the time and place to tell you.” He drew away
almost as his hand was ready to clasp hers—all because her sweet
eyes met his trustingly—lovingly.
“Just now I am a poor little reprobate,” she sighed ever so
miserably. “You are very good. I'll not forget.”
“I 'll not permit you to forget,” he said eagerly.
“Is n't the housekeeper a long time in coming?” she asked quickly.
He laughed contentedly.
“We've no reason to worry about her. It 's the pursuers from
Bazelhurst that should trouble us. Won't you tell me the whole
story?” And she told him everything, sitting there beside him with a
hot drink in her hand and a growing shame in her heart. It was
dawning upon her with alarming force that she was exposing a
hitherto unknown incentive. It was not a comfortable awakening.
“And you champion me to that extent?” he cried joyously. She
nodded bravely and went on.
“So here I am,” she said in conclusion. “I really could not have
walked to Ridgely to-night, could I?”
“I should say not.”
“And there was really nowhere else to come but here?” dubiously.
“See that light over there—up the mountain?” he asked, leading
her to a window. “Old man Grimes and his wife live up there. They
keep a light burning all night to scare Renwood's ghost away. By
Jove, the storm will be upon us in a minute. I thought it had blown
around us.” The roll of thunder came up the valley. “Thank heaven,
you 're safe indoors. Let them pursue if they like. I 'll hide you if
they come, and the servants are close-mouthed.”
“I don't like the way you put it, Mr. Shaw.”
“Hullo, hullo—the house,” came a shout from the wind-ridden
night outside. Two hearts inside stopped beating for a second or
two. She caught her breath sharply as she clasped his arm.
“They are after me!” she gasped.
“They must not find you here. Really, Miss Drake, I mean it. They
would n't understand. Come with me. Go down this hall quickly. It
leads to the garden back of the house. There's a gun-room at the
end of the hall. Go in there, to your right. Here, take this! It's an
electric saddle-lantern. I 'll head these fellows off. They shan't find
you. Don't be alarmed.”
She sped down the narrow hall and he, taking time to slip into a
long dressing-coat, stepped out upon the porch in response to the
now prolonged and impatient shouts.
“Who 's there?” he shouted. The light from the windows revealed
several horsemen in the roadway.
“Friends,” came back through the wind. “Let us in out of the
storm. It's a terror.”
“I don't know you.” There was a shout of laughter and some
profanity.
“Oh, yes you do, Mr. Shaw. Open up and let us in. It's Dave Rank
and Ed Hunter. We can't make the cabin before the rain.” Shaw could
see their faces now and then by the flashes of lightning and he
recognized the two woodsmen, who doubtless had been visiting
sweethearts up toward Ridgely.
“Take your horses to the stable, boys, and come in,” he called,
laughing heartily. Then he hurried off to the gun-room. He passed
Mrs. Ulrich coming downstairs yawning prodigiously; he called to her
to wait for him in the library.
There was no one in the gun-room; the door leading to the back
porch was open.
With an exclamation he leaped outside and looked about him.
“Good heavens!” he cried, staggering back.
Far off in the night, a hundred yards or more up the road, leading
to Grimes' cabin he saw the wobbling, uncertain flicker of a light
wending its way like a will-o'-the-wisp through the night. Without a
moment's hesitation and with something strangely like an oath, he
rushed into the house, almost upsetting the housekeeper in his
haste.
“Visitors outside. Make 'em comfortable. Back soon,” he jerked out
as he changed his coat with small respect for his injured arm. Then
he clutched a couple of raincoats from the rack and flew out of the
back door like a man suddenly gone mad.
Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster
T
CHAPTER VI—IN WHICH A GHOST
TRESPASSES
he impulse which drove Penelope out for the second time that
night may be readily appreciated. Its foundation was fear; its
subordinate emotions were shame, self-pity and consciousness
of her real feeling toward the man of the house. The true spirit of
womanhood revolted with its usual waywardness.
She was flying down the stony road, some distance from the
cottage, in the very face of the coming tornado, her heart beating
like a trip-hammer, her eyes bent on the little light up the mountain-
side, before it occurred to her that this last flight was not only
senseless but perilous. She even laughed at herself for a fool as she
recalled the tell-tale handbag on the porch and the damning
presence of a Bazelhurst lantern in the hallway.
The storm which had been raging farther down the valley was at
last whirling up to the hill-tops, long delayed as if in gleeful
anticipation of catching her alone and unprotected. The little electric
saddle-lamp that she carried gave out a feeble glow, scarce opening
the way in the darkness more than ten feet ahead. Rough and
irksome was the road, most stubborn the wall of wind. The second
threat of the storm was more terrifying than the first; at any instant
it was likely to break forth in all its slashing fury—and she knew not
whither she went.
Even as she lost heart and was ready to turn wildly back in an
effort to reach Shaw's home before the deluge, the lightning flashes
revealed to her the presence of a dwelling just off the road not two
hundred feet ahead. She stumbled forward, crying like a frightened
child. There were no lights. The house looked dark, bleak,
unfriendly. Farther up the hillside still gleamed the little light that
was meant to keep Renwood's ghost from disturbing the slumbers of
old man Grimes and his wife. She could not reach that light, that
much she knew. Her feet were like hundredweights, her limbs
almost devoid of power; Grimes' hut appeared to be a couple of
miles away.
With a last, breathless effort, she turned off the road and
floundered through weeds and brush until she came to what proved
to be the rear of the darkened house. Long, low, rangy it reached off
into the shadows, chilling in its loneliness. There was no time left for
her to climb the flight of steps and pound on the back door. The rain
was swishing in the trees with a hiss that forbade delay.
She threw herself, panting and terror-stricken, into the cave-like
opening under the porch, her knees giving way after the supreme
effort. The great storm broke as she crouched far back against the
wall; her hands over her ears, her eyes tightly closed. She was safe
from wind and rain, but not from the sounds of that awful conflict.
The lantern lay at her feet, sending its ray out into the storm with
the senseless fidelity of a beacon light.
“Penelope!” came a voice through the storm, and a second later a
man plunged into the recess, crashing against the wall beside her.
Something told her who it was, even before he dropped beside her
and threw his strong arm about her shoulders. The sound of the
storm died away as she buried her face on his shoulder and shivered
so mightily that he was alarmed. With her face burning, her blood
tingling, she lay there and wondered if the throbbing of her heart
were not about to kill her.
He was crying something into her ear—wild, incoherent words that
seemed to have the power to quiet the storm. And she was
responding—she knew that eager words were falling from her lips,
but she never knew what they were—responding with a fervour that
was overwhelming her with joy. Lips met again and again and there
was no thought of the night, of the feud, the escapade, the
Renwood ghost—or of aught save the two warm living human bodies
that had found each other.
The storm, swerving with the capricious mountain winds, suddenly
swept their refuge with sheets of water. Randolph Shaw threw the
raincoats over his companion and both laughed hysterically at their
plight, suddenly remembered.
“We can't stay here,” he shouted.
“We can't go out into it,” she cried.
“Where are we?”
“Renwood's,” he called back. Their position was untenable. He was
drenched; the raincoats protected her as she crouched back into the
most remote corner. Looking about, he discovered a small door
leading to the cellar. It opened the instant he touched the latch.
“Come, quick,” he cried, lifting her to her feet. “In here—stoop! I
have the light. This is the cellar. I'll have to break down a door
leading to the upper part of the house, but that will not be difficult.
Here's an axe or two. Good Lord, I'm soaked!”
“Whe—where are we going?” she gasped, as he drew her across
the earthern floor.
“Upstairs. It's comfortable up there.” They were at the foot of the
narrow stairway. She held back.
“Never! It's the—the haunted house! I can't—Randolph.”
“Pooh! Don't be afraid. I'm with you, dearest.”
“I know,” she gulped, “only one arm. Oh, I can't!”
“It's all nonsense about ghosts. I've slept here twenty times,
Penelope. People have seen my light and my shadow, that 's all. I'm
a pretty substantial ghost.”
“Oh, dear! What a disappointment. And there are no spooks? Not
even Mrs. Renwood?”
“Of course she may come back, dear, but you'd hardly expect a
respectable lady spook to visit the place with me stopping here.
Even ghosts have regard for conventionalities. She could n't—”
“How much more respectable than I,” Penelope murmured
plaintively.
“Forgive me,” he implored. “I would—only you are so wet.”
The door above was locked, but Shaw swung the axe so
vigorously that any but a very strong-nerved ghost must have been
frightened to death once more.
“It's my house, you know,” he explained from the top step. “There
we are! Come up, Penelope. The fort is yours.”
She followed him into the hall above. In silence they walked along
the bare floors through empty rooms until at last he opened a door
in what proved to be the left wing. To her surprise, this room was
comfortably furnished. There were ashes in the big fireplace and
there were lamps which had been used recently—for they were filled
with oil.
“Here's where I read sometimes,” he explained. “I have slept on
that couch. Last winter I came up here to hunt. My cottage wasn't
finished, so I stayed here.
“I'll confess I've heard strange sounds—now, don't shiver! Once or
twice I've been a bit nervous, but I'm still alive, you see.” He lighted
the wicks in the two big lamps while she looked on with the chills
creeping up and down her back. “I'll have a bully fire in the fireplace
in just a minute.”
“Let me help you,” she suggested, coming quite close to him with
uneasy glances over her shoulders.
Ten minutes later they were sitting before a roaring fire, quite
content even though there was a suggestion of amazed ghosts
lurking in the hallway behind them. No doubt old man Grimes and
his wife, if they awoke in the course of the night, groaned deep
prayers in response to the bright light from the windows of the
haunted house. Shaw and Penelope smiled securely as they listened
to the howling storm outside.
“Well, this is trespassing,” she said, beaming a happy smile upon
him.
“I shall be obliged to drive you out, alas,” he said reflectively. “Do
you recall my vow? As long as you are a Bazelhurst, I must perforce
eject you.”
“Not to-night!” she cried in mock dismay.
“But, as an alternative, you'll not be a Bazelhurst long,” he went
on eagerly, suddenly taking her hands into his, forgetful of the
wounded left. “I'm going to try trespassing myself. To-morrow I 'm
going to see your brother. It 's regular, you know. I'm going to tell
the head of your clan that you are coming over to Shaw, heart and
hand.”
“Oh!” she exclaimed. “You—you—no, no! You must not do that!”
“But, my dear, you are going to marry me.”
“Yes—I—suppose so,” she murmured helplessly. “That is n't what I
meant. I mean, it is n't necessary to ask Cecil. Ask me; I'll consent
for him.”
Half an hour passed. Then he went to the window and looked out
into the storm.
“You must lie down and get some sleep,” he insisted, coming back
to her. “The storm's letting up, but we can't leave here for quite a
while. I'll sit up and watch. I'm too happy to sleep.” She protested,
but her heavy eyes were his allies. Soon he sat alone before the fire;
she slept sound on the broad couch in the corner, a steamer rug
across her knees. A contented smile curved his lips as he gazed
reflectively into the flames. He was not thinking of Mrs. Renwood's
amiable ghost.
How long she had been asleep, Penelope did not know. She awoke
with a start, her flesh creeping. A nameless dread came over her;
she felt that she was utterly alone and surrounded by horrors. It was
a full minute—a sickening hour, it seemed—before she realized that
she was in the room with the man she loved. Her frightened eyes
caught sight of him lying back in the chair before the dying fire in
the chimney place. The lights were low, the shadows gaunt and chill.
A terrified exclamation started to her lips. Her ears again caught
the sound of some one moving in the house—some alien visitor.
There was no mistaking the sound—the distant, sepulchral laugh
and the shuffling of feet, almost at the edge of the couch it seemed.
“Randolph!” she whispered hoarsely. The man in the chair did not
move. She threw off the blanket and came to a sitting posture on
the side of the couch, her fingers clutching the covering with tense
horror. Again the soft, rumbling laugh and the sound of footsteps on
the stairway. Like a flash she sped across the room and clutched
frantically at Randolph's shoulders. He awoke with an exclamation,
staring bewildered into the horrified face above.
“The—the ghost!” she gasped, her eyes glued upon the hall door.
He leaped to his feet and threw his arms about her.
“You've had a bad dream,” he said. “What a beast I was to fall
asleep. Lord, you're frightened half out of your wits. Don't tremble
so, dearest. There's no ghost. Every one knows—”
“Listen—listen!” she whispered. Together they stood motionless,
almost breathless before the fire, the glow from which threw their
shadows across the room to meet the mysterious invader.
“Good Lord,” he muttered, unwilling to believe his ears. “There is
some one in the house. I 've—I've heard sounds here before, but
not like these.” Distinctly to their startled ears came the low,
subdued murmur of a human voice and then unmistakable moans
from the very depth of the earth—from the grave, it seemed.
“Do you hear?” she whispered. “Oh, this dreadful place! Take me
away, Randolph, dear,—”
“Don't be afraid,” he said, drawing her close. “There's nothing
supernatural about those sounds. They come from lips as much alive
as ours. I 'll investigate.” He grabbed the heavy poker from the
chimney corner, and started toward the door. She followed close
behind, his assurance restoring in a measure the courage that had
temporarily deserted her.
In the hallway they paused to look out over the broad porch. The
storm had died away, sighing its own requiem in the misty tree-tops.
Dawn was not far away. A thick fog was rising to meet the first
glance of day. In surprise Shaw looked at his watch, her face at his
shoulder. It was after five o'clock.
“Ghosts turn in at midnight, dear,” he said with a cheerful smile.
“They don't keep such hours as these.”
“But who can it be? There are no tramps in the mountains,” she
protested, glancing over her shoulder apprehensively.
“Listen! By Jove, that voice came from the cellar.”
“And the lock is broken,” she exclaimed. “But how silly of me!
Ghosts don't stop for locks.”
“I 'll drop the bolts just the same,” he said, as they hurried down
the hallway. At the back stairs they stopped and listened for many
minutes. Not a sound came up to them from below. Softly he closed
the door and lowered two heavy bars into place. “If there's any one
down there they probably think they've heard spooks trotting around
up here.”
“Really, it's quite thrilling, isn't it?” she whispered, in her
excitement.
“In any event, we're obliged to remain under cover until they
depart,” he said thoughtfully. “We can't be seen here, dearest.”
“No,” she murmured, “not even though it is our house.”
They returned to the big room as softly as mice and he left her a
moment later to close the heavy window shutters on the porch.
When he returned there was a grim smile on his face and his voice
shook a little as he spoke.
“I've heard the voices again. They came from the laundry, I think.
The Renwoods were downright Yankees, Penelope; I will swear that
these voices are amazingly English.”
T
CHAPTER VII—IN WHICH THE
AUTHOR TRESPASSES
HIS narrative has quite as much to do with the Bazelhurst side
of the controversy as it has with Shaw's. It is therefore but fair
that the heroic invasion by Lord Cecil should receive equal
consideration from the historian. Shaw's conquest of one member of
the force opposing him was scarcely the result of bravery; on the
other hand Lord Cecil's dash into the enemy's country was the very
acme of intrepidity. Shaw had victory fairly thrust upon him; Lord
Bazelhurst had a thousand obstacles to overcome before he could
even so much as stand face to face with the enemy. Hence the
expedition that started off in the wake of the deserter deserves more
than passing mention.
Down the drive and out into the mountain road clattered the three
horsemen. Lady Bazelhurst, watching at the window casement,
almost swooned with amazement at the sight of them. The capes of
their mackintoshes seemed to flaunt a satirical farewell in her face;
their owners, following the light of the carriage lamps, swept from
view around a bend in the road.
His lordship had met the duke in the hall, some distance from that
nobleman's room, and, without observing Barminster's apparent
confusion, commanded him to join in the pursuit. Barminster
explained that he was going to see how the cook was resting;
however, he would go much farther to be of service to the runaway
sister of his host.
“She's broken-hearted,” half sobbed the brother.
“Yes,” agreed the duke; “and what's a broken leg to a broken
heart? Penelope's heart, at that. Demme, I can't find the cook's
room, anyway.”
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

PDF
Introduction to GitHub Actions – How to easily automate and integrate with Gi...
PDF
Intro to GitHub Actions
PDF
Introduction to GitHub Actions
PDF
Introduction to GitHub Actions - How to easily automate and integrate with Gi...
PDF
Hands-on GitHub Actions 1st Edition Chaminda Chandrasekara
PDF
Learning GitHub Actions 1 / converted Edition Brent Laster
PDF
Learning GitHub Actions: Automation and Integration of CI/CD with GitHub 1st ...
PDF
Introduction to Github Actions
Introduction to GitHub Actions – How to easily automate and integrate with Gi...
Intro to GitHub Actions
Introduction to GitHub Actions
Introduction to GitHub Actions - How to easily automate and integrate with Gi...
Hands-on GitHub Actions 1st Edition Chaminda Chandrasekara
Learning GitHub Actions 1 / converted Edition Brent Laster
Learning GitHub Actions: Automation and Integration of CI/CD with GitHub 1st ...
Introduction to Github Actions

Similar to Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster (20)

PDF
Introduction to Github Actions
PDF
Introduction to GitHub Actions
PDF
Learning GitHub Actions 1 / converted Edition Brent Laster
PDF
GitHub Actions in Action MEAP V03 Michael Kaufmann
PDF
GitHub Actions in Action MEAP V03 Michael Kaufmann
PPTX
Introduction to Github action Presentation
PDF
GitHubActionGitHubActionGitHubAction.pdf
PDF
(Ebook) Learning GitHub Actions: Automation and Integration of CI/CD with Git...
PPTX
Github in Action
PDF
GitHub Actions in action
PPTX
GitHub Actions Security - DDOG
PPTX
GitHub Actions Security
PPTX
GitHub Actions: your free CI engine (and much more)
PDF
Demystifying GitHub Actions - Harnessing the power of automation to streamlin...
PPTX
CICD Pipeline Using Github Actions
PPTX
Group - 9 _ Github Actions.pptx
PDF
DevOps Fest 2020. Alexey Golub. GitHub Actions in action
PPTX
GITHUB_ACTIONS_CICD_OVERVIEW_FOR_BEGINNERS
PDF
Accelerate Microservices Deployments with Automation
PDF
Intro to Github Actions @likecoin
Introduction to Github Actions
Introduction to GitHub Actions
Learning GitHub Actions 1 / converted Edition Brent Laster
GitHub Actions in Action MEAP V03 Michael Kaufmann
GitHub Actions in Action MEAP V03 Michael Kaufmann
Introduction to Github action Presentation
GitHubActionGitHubActionGitHubAction.pdf
(Ebook) Learning GitHub Actions: Automation and Integration of CI/CD with Git...
Github in Action
GitHub Actions in action
GitHub Actions Security - DDOG
GitHub Actions Security
GitHub Actions: your free CI engine (and much more)
Demystifying GitHub Actions - Harnessing the power of automation to streamlin...
CICD Pipeline Using Github Actions
Group - 9 _ Github Actions.pptx
DevOps Fest 2020. Alexey Golub. GitHub Actions in action
GITHUB_ACTIONS_CICD_OVERVIEW_FOR_BEGINNERS
Accelerate Microservices Deployments with Automation
Intro to Github Actions @likecoin
Ad

Recently uploaded (20)

PDF
Module 4: Burden of Disease Tutorial Slides S2 2025
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PPTX
Lesson notes of climatology university.
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
PPTX
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
PPTX
GDM (1) (1).pptx small presentation for students
PPTX
PPH.pptx obstetrics and gynecology in nursing
PDF
RMMM.pdf make it easy to upload and study
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PPTX
Pharma ospi slides which help in ospi learning
PDF
Insiders guide to clinical Medicine.pdf
PDF
Sports Quiz easy sports quiz sports quiz
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
PPTX
Cell Types and Its function , kingdom of life
PDF
Pre independence Education in Inndia.pdf
PDF
Basic Mud Logging Guide for educational purpose
PDF
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
PDF
Complications of Minimal Access Surgery at WLH
Module 4: Burden of Disease Tutorial Slides S2 2025
Renaissance Architecture: A Journey from Faith to Humanism
Lesson notes of climatology university.
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
FourierSeries-QuestionsWithAnswers(Part-A).pdf
Introduction_to_Human_Anatomy_and_Physiology_for_B.Pharm.pptx
GDM (1) (1).pptx small presentation for students
PPH.pptx obstetrics and gynecology in nursing
RMMM.pdf make it easy to upload and study
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Final Presentation General Medicine 03-08-2024.pptx
Pharma ospi slides which help in ospi learning
Insiders guide to clinical Medicine.pdf
Sports Quiz easy sports quiz sports quiz
102 student loan defaulters named and shamed – Is someone you know on the list?
Cell Types and Its function , kingdom of life
Pre independence Education in Inndia.pdf
Basic Mud Logging Guide for educational purpose
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
Complications of Minimal Access Surgery at WLH
Ad

Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster

  • 1. Learning Github Actions Automation And Integration Of Cicd With Github 1st Edition Brent Laster download https://ebookbell.com/product/learning-github-actions-automation- and-integration-of-cicd-with-github-1st-edition-brent- laster-52341142 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Learning Github Actions 1 Converted Brent Laster https://ebookbell.com/product/learning-github-actions-1-converted- brent-laster-51775146 Learning Github Actions Second Early Release Brent Laster https://ebookbell.com/product/learning-github-actions-second-early- release-brent-laster-46543062 Learning Github Actions Brent Laster https://ebookbell.com/product/learning-github-actions-brent- laster-232271096 Aiassisted Programming For Web And Machine Learning Improve Your Development Workflow With Chatgpt And Github Copilot Christoffer Noring https://ebookbell.com/product/aiassisted-programming-for-web-and- machine-learning-improve-your-development-workflow-with-chatgpt-and- github-copilot-christoffer-noring-59791118
  • 3. Machine Learning Simplified A Gentle Introduction To Supervised Learning 1011 Andrew Wolf https://ebookbell.com/product/machine-learning-simplified-a-gentle- introduction-to-supervised-learning-1011-andrew-wolf-42568766 Learning https://ebookbell.com/product/learning-35537428 Learning Cognitivebehavior Therapy An Illustrated Guide 2nd Edition 2nd Edition Jesse H Wright https://ebookbell.com/product/learning-cognitivebehavior-therapy-an- illustrated-guide-2nd-edition-2nd-edition-jesse-h-wright-44880782 Learning Tagalog Fluency Made Fast And Easy Course Book 1 Part Of 7book Set 2nd Edition Frederik De Vos https://ebookbell.com/product/learning-tagalog-fluency-made-fast-and- easy-course-book-1-part-of-7book-set-2nd-edition-frederik-de- vos-44939110 Learning Tagalog Fluency Made Fast And Easy Course Book 3 Part Of 7book Set Bw Free Audio Download 2nd Edition Frederik De Vos https://ebookbell.com/product/learning-tagalog-fluency-made-fast-and- easy-course-book-3-part-of-7book-set-bw-free-audio-download-2nd- edition-frederik-de-vos-44939112
  • 5. Brent Laster Foreword by Julian C. Dunn Learning GitHub Actions Automation and Integration of CI/CD with GitHub
  • 6. GITHUB “Whether you are new to CI/CD and starting with GitHub Actions as your first product in this space or are already a CI/CD expert and migrating from another tool, Brent’s book has the right balance of information to help you become productive quickly.” —Julian C. Dunn Senior Director of Project Management, GitHub Actions ”If you’re looking to master automation in software development, Learning GitHub Actions is a comprehensive guide you can’t miss.” —Taylor Dolezal Head of Ecosystem, CNCF Learning GitHub Actions Twitter: @oreillymedia linkedin.com/company/oreilly-media youtube.com/oreillymedia Maximize your software development productivity with GitHub Actions, the continuous integration and automation platform that works seamlessly with GitHub. With this practical book, author Brent Laster shows software developers, SREs, and DevOps engineers how to gain the maximum benefit from Actions. You’ll learn how to leverage this feature in your daily work with GitHub to achieve greater simplification, standardization, and automation. This book explains the platform, components, use cases, implementation, and integration points of actions, so you can leverage them to provide the functionality and features that today’s complex pipelines and software development processes need. You’ll learn how to design and implement automated workflows that respond to common events like pushes, pull requests, and review updates—and how to use Actions to implement functionality from simple validation to complex pipelines. You’ll learn how to: • Understand the structure, syntax, and semantics of GitHub Actions • Incorporate actions into your automation and processes • Create custom actions with Docker, JavaScript, or shell approaches • Troubleshoot and debug workflows that use actions • Combine actions with GitHub APIs and other integration options • Securely implement workflows with GitHub Actions • Migrate from using other CI/CD platforms to GitHub Actions Brent Laster is an R&D DevOps director at SAS. He is a global trainer, author, and speaker on open source technologies. US $65.99 CAN $82.99 ISBN: 978-1-098-13107-4
  • 7. Brent Laster Foreword by Julian C. Dunn Learning GitHub Actions Automation and Integration of CI/CD with GitHub Boston Farnham Sebastopol Tokyo Beijing Boston Farnham Sebastopol Tokyo Beijing
  • 8. 978-1-098-13107-4 [LSI] Learning GitHub Actions by Brent Laster Copyright © 2023 Tech Skills Transformations, LLC. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (https://oreilly.com). For more information, contact our corporate/institu‐ tional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: John Devins Development Editor: Michele Cronin Production Editor: Jonathon Owen Copyeditor: Piper Editorial Consulting, LLC Proofreader: Kim Wimpsett Indexer: Ellen Troutman-Zaig Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea August 2023: First Edition Release History for the First Edition 2023-08-16: First Release See https://oreilly.com/catalog/errata.csp?isbn=9781098131074 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Learning GitHub Actions, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the author and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.
  • 9. To all my family and friends who have helped me write the best chapters of my life.
  • 11. Table of Contents Foreword. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii Part I. Foundations 1. The Basics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 What Is GitHub Actions? 4 Automation Platform 4 Framework 5 What Are the Use Cases for GitHub Actions? 6 Starter Workflows 7 Actions Marketplace 8 What Costs Are Involved? 10 The Free Model 10 The Paid Model 10 When Does Moving to GitHub Actions Make Sense? 13 Investment in GitHub 13 Use of Public Actions 13 Creating Your Own Actions 13 Artifact Management 13 Action Management 14 Conclusion 14 2. How Does Actions Work?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 An Overview 15 Triggering Workflows 17 v
  • 12. Components 19 Steps 19 Runners 20 Jobs 20 Workflow 21 Workflow Execution 22 Conclusion 24 3. What’s in an action?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 The Structure of an action 26 Interfacing with actions 29 Using actions 32 Public actions and the Marketplace 32 Conclusion 36 4. Working with Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Creating the First Workflow in a Repository 37 Committing the Initial Workflow 42 Using the VS Code GitHub Actions Extension 59 Conclusion 65 5. Runners. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 GitHub-Hosted Runners 67 What’s in the Runner Images? 69 Adding Additional Software on Runners 71 Self-Hosted Runners 72 Requirements for Self-Hosted Runners 73 Limits for Self-Hosted Runners 74 Security Considerations for Using Self-Hosted Runners 74 Setting Up a Self-Hosted Runner 75 Using a Self-Hosted Runner 78 Using Labels with Self-Hosted Runners 79 Troubleshooting Self-Hosted Runners 80 Removing a Self-Hosted Runner 82 Autoscaling Self-Hosted Runners 86 Just-in-Time Runners 86 Conclusion 86 vi | Table of Contents
  • 13. Part II. Building Blocks 6. Managing Your Workflow Environments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Naming Your Workflow and Workflow Runs 91 Contexts 93 Environment Variables 94 Default Environment Variables 95 Secrets and Configuration Variables 97 Managing Permissions for Your Workflow 103 Deployment Environments 105 Conclusion 115 7. Managing Data Within Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Working with Inputs and Outputs in Workflows 118 Defining and Referencing Workflow Inputs 118 Capturing Output from a Step 119 Capturing Output from a Job 120 Capturing Output from an Action Used in a Step 121 Defining Artifacts 122 Uploading and Downloading Artifacts 123 Adding Parameters 127 Using Caches in GitHub Actions 135 Using the Explicit Cache Action 136 Monitoring Caches 141 Activating a Cache with a Setup Action 143 Conclusion 145 8. Managing Workflow Execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Advanced Triggering from Changes 147 Triggering Based on Activity Types 148 Using Filters to Refine Triggers 150 Triggering Workflows Without a Change 152 Dealing with Concurrency 156 Running a Workflow with a Matrix 159 Workflow Functions 160 Conditionals and Status Functions 161 Conclusion 163 Table of Contents | vii
  • 14. Part III. Security and Monitoring 9. Actions and Security. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Security by Configuration 168 Managing Execution of Workflows from Pull Requests 173 Workflow Permissions 174 The CODEOWNERS File 175 Protected Tags 176 Protected Branches 177 Repository Rules 178 Security by Design 181 Secrets 181 Securing Secrets 182 Tokens 183 Dealing with Untrusted Input 191 Securing Your Dependencies 199 Security by Monitoring 201 Scanning 202 Processing Pull Requests Securely 205 Vulnerabilities with Workflows in Pull Requests 207 Vulnerabilities with Source Code in Pull Requests 212 Adding a Pull Request Validation Script 215 Safely Handling Pull Requests 218 Conclusion 220 10. Monitoring, Logging, and Debugging. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Gaining More Observability 223 Understanding Status at a High Level 224 Creating Status Badges for Workflows 226 Working with Past States 232 Mapping Workflow Versions to Runs 232 Re-running Jobs in a Workflow 234 Debugging Workflows 241 Step Debug Logging 242 Debugging the Runner Environment 245 Activating Debugging 248 Augmenting and Customizing Logging 249 Adding Your Own Messages in Logs 249 Additional Log Customizations 251 Creating a Customized Job Summary 253 Conclusion 256 viii | Table of Contents
  • 15. Part IV. Advanced Topics 11. Creating Custom actions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 Anatomy of an action 260 Types of Actions 263 Composite Action 263 Docker Container Action 267 Creating a JavaScript Action 271 Completing Your Action Creation 274 Publishing Actions on the GitHub Marketplace 276 Updating Actions on the Marketplace 282 Removing an Action from the Marketplace 285 The Actions Toolkit 285 Using Workflow Commands from the Toolkit 286 Local actions 289 Conclusion 291 12. Advanced Workflows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 Creating Your Own Starter Workflows 293 Creating a Starter Workflow Area 295 Creating a Starter Workflow File 295 Adding Supporting Pieces 297 Using the New Starter Workflow 299 Reusable Workflows 300 Inputs and Secrets 303 Outputs 305 Limitations 306 Required Workflows 308 Constraints 308 Example 309 Execution 313 Conclusion 315 13. Advanced Workflow Techniques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 Driving GitHub from Your Workflow 317 Using the GitHub CLI 318 Creating Scripts 319 Invoking GitHub APIs 320 Using a Matrix Strategy to Automatically Create Jobs 322 One-Dimensional Matrices 322 Multi-dimensional Matrices 323 Including Extra Values 327 Table of Contents | ix
  • 16. Excluding Values 328 Handling Failure Cases 329 Defining Max Concurrent Jobs 330 Using Containers in Your Workflow 330 Using a Container as the Environment for a Job 331 Using a Container with a Step 333 Running Containers as Services in a Job 334 Conclusion 335 14. Migrating to GitHub Actions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Prep 338 Source Code 338 Automation 340 Infrastructure 340 Users 341 Azure Pipelines 342 CircleCI 344 GitLab CI/CD 346 Jenkins 348 Travis CI 351 GitHub Actions Importer 353 Authentication 354 Planning 355 Build Steps and Related 357 Manual Tasks 359 File Manifest 360 Forecasting 361 Doing a Dry Run 363 Creating Custom Transformers for the Importer 364 Doing the Actual Migration 369 Conclusion 373 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 x | Table of Contents
  • 17. Foreword The fundamental concepts of continuous integration/continuous delivery (CI/CD) have now been around for several decades, since Martin Fowler and Matthew Foem‐ mel of Thoughtworks first popularized CI in their seminal essay of September 2000, and Jez Humble and Dave Farley wrote about CD in their 2010 book Continuous Delivery: Reliable Software Releases Through Build, Test, and Deployment Automation (Addison-Wesley Professional). Yet it has taken years for widespread adoption of tools for CI/CD and for the notion of a software delivery pipeline to take root. I believe this is because three fundamental socio-technical changes in how we do soft‐ ware development had to occur first: • Development had to become collaborative, rather than performed by isolated, individual engineers. This was driven first by a truly distributed version control system (Git) and then accelerated through pull-request platforms like GitHub. • Widespread adoption of agile practices needed to occur. Motivated by metrics from DevOps leaders like DevOps Research Associates (DORA) that, contrary to intuition, showed more frequent delivery of smaller changes reduces risk, savvy engineering leaders drove the implementation of frequently used build pipelines where software was continuously built, tested, and deployed directly to custom‐ ers—sometimes dozens of times per day. • The overburdening of traditional IT operations functions with increased com‐ plexity drove massive cultural changes via the DevOps movement. This led to a you-build-it, you-own-it approach to software operations where, increasingly, developers take full ownership for the success, failure, and performance of their software in production, rather than throwing code over the wall to a release engi‐ neering team that would operate a build process and somehow “add quality” to software that didn’t have it already. All these changes mean that GitHub Actions, as a relatively recent entrant to the CI/CD pipeline and automation category, is a substantially different product from xi
  • 18. incumbents. It is natively integrated into GitHub, making it a natural fit for develop‐ ers who are already familiar with storing their source code there. GitHub Actions is also designed around the concept of a workflow, which can be used to create CI/CD pipelines but also handle any other kind of software automation tasks like managing open issues and tasks that open source and enterprise developers alike need to per‐ form in the course of their work. Finally, GitHub Actions, as the name would suggest, is based on the notion of an action: a reusable component that helps to encapsulate common tasks and reduce repetition when authoring workflows. The GitHub Mar‐ ketplace offers nearly 20,000 actions at the time of writing, making it easy for devel‐ opers, DevOps engineers, and site reliability engineers to get started with any kind of build automation task. Although GitHub Actions is a sophisticated product, learning it doesn’t need to be complicated. Brent Laster has written an excellent book that relies on progressive dis‐ closure, starting with the most basic concepts to get you up and running with GitHub Actions while also providing a comprehensive tour of GitHub Actions’ most advanced features to help you to optimize your use of the product as you adopt it across your organization. My team and I have been delighted to partner with Brent in ensuring that the content covered here is as current as possible. Whether you are new to CI/CD and starting with GitHub Actions as your first product in this space or are already a CI/CD expert and migrating from another tool, Brent’s book has the right balance of information to help you become productive quickly. We wish you the greatest success in automating your software delivery processes. — Julian C. Dunn Senior Director of Product Management GitHub Actions xii | Foreword
  • 19. Preface Releasing software should be easy.… Automate almost everything, and keep everything you need to build, deploy, test, and release your application in version control. —David Farley, Continuous Delivery: Reliable Software Releases Through Build, Test, and Deployment Automation Back in 1968, the London Underground in the United Kingdom needed a digital sign to warn passengers to be careful while crossing the gaps between train doors and sta‐ tion platforms. Since data storage for such signs was very expensive back in the day, they chose a very short phrase to help keep riders alert: “mind the gap.” These days, the word “mind” is less commonly used, but the intent to bring awareness to missing parts or things that can trip you up and to act on them is still meaningful. And it is just as important when we apply the idea to business and technical processes that can benefit from automation. From its inception in 2008, GitHub has filled gaps in terms of allowing users to col‐ laborate and build communities around open source software. And it has done this very well. It is challenging not to overestimate the significance of the SaaS hosting model that GitHub pioneered and the collaborative ecosystem it has built around it. Yet up until a few years ago, there was one key piece of that ecosystem that was clearly missing—a tightly integrated automation platform for key functions like CI/CD. Certainly, there has been no shortage of applications that have worked to fill that gap. Tools such as Jenkins, Travis CI, CircleCI, Azure DevOps, and more have provided integration methods through various approaches such as webhooks. However, users of GitHub still had to go outside their collaboration environment to use another application to get the basic functionality they needed. All of that has changed with the addition of GitHub Actions. Actions is challenging to classify with a standalone designation. It is a logical exten‐ sion of the larger GitHub model. And while this is not a general book on GitHub, I have tried to write it in such a way that you can see how GitHub Actions plays with xiii
  • 20. the larger GitHub ecosystem, regardless of your experience level with automation in GitHub. The Structure of This Book Since you’re reading this book, I imagine you’re at least somewhat curious and per‐ haps even excited about the potential of Actions. I’ve tried to capture that potential along with the relevant details throughout the text. So let me tell you a bit about the organization of this Learning GitHub Actions book and how you can get the most out of it. Part I: Foundations As with any technical journey, we start off discussing the foundations of GitHub Actions. Part I of the book covers the basics of what GitHub Actions is and how it works, and it helps you understand its core pieces and how to navigate its flow. My intent here is to answer the basic why and how questions that you need to know to get up and running with the technology, while providing you the insight and under‐ standing to establish the firm footing to launch your use of actions on. Part II: Building Blocks Part II extends your depth of knowledge on Actions with the building blocks to take advantage of the wider range of options available to you for configuration, sharing and storing data, and triggering and controlling the execution of your workflows. These techniques form the core of using actions to get your tasks done, while show‐ ing you how to customize their use to best suit your needs. Part III: Security and Monitoring Use of a technology includes the explicit requirement to use it securely. And the need to understand the security aspects of any new technology is critical. So Part III of the book discusses the key areas of security and monitoring. This section looks at security from the triple lenses of configuration, design, and monitoring. Then it further delves into monitoring in its own right, by describing the different options available for log‐ ging and the techniques available to you for debugging issues. Part IV: Advanced Topics When you’re ready for more advanced interaction with Actions, Part IV provides insight on a number of less typical (but arguably more fun) topics. These include cre‐ ating your own custom actions, creating your own starter workflows and reusable workflows, working with the GitHub CLI, APIs, and using matrix strategies and con‐ tainers in your workflows. And to finish up, I’ve included some practical tips and xiv | Preface
  • 21. examples of how to migrate to GitHub Actions if you’re using another automation toolset. The book’s last chapter also includes an in-depth review and examples of the new GitHub Importer tool to help bootstrap and automate migrations. With this general structure in mind, the next section provides a further breakdown by audience type. Intended Audience This book is for anyone who is trying to learn more about GitHub Actions. If you’re picking this book up, you should already have a basic knowledge of Git and GitHub, and now you’re trying to figure out how to implement Actions into your workflow. You likely have some experience with solutions like Jenkins, Travis CI, and so on, and the automation platform and framework of GitHub Actions may improve your soft‐ ware development lifecycle process. You might be a software developer, SRE, DevOps engineer, or something else entirely, but it is my hope that the sections outlined above will provide a complete learning solution for GitHub Actions for all readers. Here are some audiences that I had in mind while writing it and that I think can benefit from it: • Those who are new (or newish) to GitHub and looking to understand how the automation component of it works • Those who already understand the concepts and flow of GitHub Actions and want or need assistance with actually implementing the code and syntax for workflows • Those who want to understand and evaluate GitHub Actions as a potential CI/CD/automation target • Those who already have some experience with GitHub Actions and want to lev‐ erage it more fully for custom purposes • Those who are working on implementing or have implemented GitHub Actions and need to make sure they do it securely • Those who are responsible for, or want to, roll out GitHub Actions across a department, organization, or unit • Those who are experienced GitHub users and want to migrate their current CI/CD solutions to GitHub Actions If one of these fits your use case, I hope the book will provide you with the value you’re looking for. If you read it and have the opportunity, feedback is always wel‐ come through reviews or interactions at future conferences or training venues. Preface | xv
  • 22. Continuing with GitHub Actions Of course, technology continues to evolve, and we can predict it will evolve more quickly in some areas than in others. Thus you will notice that some sections of the text include disclaimers that reference “as of the time of writing.” While GitHub and I have worked together to make this book comprehensive and as current as possible as of the time of writing, you should always consult the current GitHub documentation to get the most timely information—especially on features that are currently marked beta. Fortunately, the text contains many links to the current GitHub documentation for relevant areas. Over a decade of use in various forms has shown that continuous, automated pro‐ cesses are durable models in the industry, proving out their long-term potential, relia‐ bility, and adaptability. Over time, the tooling will change, and the inputs will change, and the steps will evolve. But a well-done CI/CD/automation framework will always provide the best means to produce software in a timely manner to meet the demands of the users. If you are working in GitHub, you can find no better framework to achieve that goal than GitHub Actions. I hope that this book helps you mind the gaps in your knowledge of GitHub Actions and fill them all in. Best of luck in your journey and thank you for reading. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program ele‐ ments such as variable or function names, databases, data types, environment variables, statements, and keywords. This element signifies a general note. This element indicates a warning or caution. xvi | Preface
  • 23. Using Code Examples Supplemental material (code examples, exercises, etc.) is available for download at https://github.com/techupskills/learning-github-actions. If you have a technical question or a problem using the code examples, please send email to support@oreilly.com. This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. We appreciate, but generally do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Learning GitHub Actions by Brent Laster (O’Reilly). Copyright 2023 Tech Skills Transformations, LLC, 978-1-098-13107-4.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. O’Reilly Online Learning For more than 40 years, O’Reilly Media has provided technol‐ ogy and business training, knowledge, and insight to help companies succeed. Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com. Preface | xvii
  • 24. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-889-8969 (in the United States or Canada) 707-829-7019 (international or local) 707-829-0104 (fax) support@oreilly.com https://www.oreilly.com/about/contact.html We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/learning-github-actions. For news and information about our books and courses, visit https://oreilly.com. Find us on LinkedIn: https://linkedin.com/company/oreilly-media Follow us on Twitter: https://twitter.com/oreillymedia Watch us on YouTube: https://youtube.com/oreillymedia Acknowledgments Writing a book is a serious investment. Throughout the duration of writing this one, I have invested many early mornings, late nights, and weekends researching and craft‐ ing the content. But as Learning GitHub Actions nears publication, I am also reminded of the many others who have invested their time and energy to help get it from idea to print. It is my hope that these collective efforts ultimately lead to you feeling that it is worthy of the investment you are making by reading it. I can’t thank everyone involved enough for their commitment to this project, and their support, but I will try. It has been well over a year since I first started typing out Chapter 1, and many of the individuals mentioned here have been along for all, or the biggest part, of the journey. (And if you were involved in the journey and I neglected to acknowledge you here, please excuse the oversight. I can assure you it is an unin‐ tentional cognitive slip rather than an intentional slight.) First, many thanks to John Devins, my acquisitions editor at O’Reilly who believed in, and advocated for, this book—as he has done on my behalf for so many other projects. I have truly come to respect and appreciate John’s vision and desire to pro‐ vide quality training opportunities and find new ways to bridge learning gaps. John is most often behind the scenes, but his efforts are core to much of the learning that I and other content creators get to bring to the attendees of O’Reilly Learning. xviii | Preface
  • 25. Also behind the scenes, Michele Cronin has worked tirelessly as the development edi‐ tor for this project, keeping it (and me) on track, helping resolve any potential road‐ blocks, and giving me sage advice on how to navigate any and all challenges that have come up along the way. Her advice has always been relevant and what I needed to hear at the time. But perhaps most impressive is that she has always done it with a smile on her face, as an optimistic and supportive guide in the process. I will honestly say that I have never been a fan of the editing part of writing books. But with Michele, I knew I would come away with a confident sense of how to proceed based on her experience and guidance. There are numerous other people at O’Reilly that have had a hand in the book pro‐ cess that I want to also call out. Kate Dullea did a yeoman’s share of work in reviewing all of the screenshots and images going into the book to make sure they were suitable and legible. She also provided invaluable tips for me to validate them as I was creating the content. Clare Laylock, Kim Sandoval, and Jonathan Owen have been exceptional in proofreading and clarifying the content to make it clear and readable. And thanks to Karen Montgomery for the cool cover picture and David Futato for the interior design. I next need to thank Julian C. Dunn, senior director of product management for Actions at GitHub. In any extended discussion on a technology that is supported by a company as well as a community, it is incredibly helpful to have a contact point who can help you understand the current and future direction of the technology, answer questions, and dispel confusion around topics. Julian has done all that and more as a reviewer and advisor while I’ve been building out the content. His collaboration has unquestionably helped the book become a better, more relevant text. My appreciation goes to Julian and GitHub for their active participation in making sure the content is the best and most up to date it can be as of the time of writing. (I should also note that he wrote the foreword for the book, which I hope you’ll take a moment to read if you haven’t already.) Along with Julian, I could not have asked for a better team of technical reviewers than Brent Beer, Taylor Dolezal, Kerim Satirli, and Daniel Hinojosa. Each provided very useful feedback and suggestions that helped to keep me straight on the technical top‐ ics and presentation of the material. I feel very fortunate that I was able to get the investment of time from this group and get the benefit of their collective technical backgrounds and collective eyes for detail. I also want to thank Ethan Dennis from GitHub for his collaboration on the Actions Importer tooling and process. I was very excited when I found out that this unique new tool existed. I knew quickly that the book needed to include it as part of the final chapter on migration. Ethan was incredibly helpful as I worked through examples and the use of the tool, quickly addressing any questions and issues I ran into and Preface | xix
  • 26. serving as a reviewer for that chapter. His efforts and involvement are much appreciated. As I mentioned earlier, the work on this book was done mainly on mornings and weekends—outside of my full-time job as a director in the DevOps organization at SAS. But it is only because of the support of my coworkers and management at SAS that I am able to keep my feet in both the corporate and open source worlds. I espe‐ cially want to thank Rob Stephens for his mentorship on getting things done, his attempts to help me learn to write concisely for business communications (which I am still working towards), and his support for leveraging my training and writing interests as a part of my job at SAS. Also thanks to Jared Peterson for his leadership, support, and focus on open-source opportunities, and Bryan Harris—our incredible CTO and EVP—for his examples of technical and people leadership and support. I would be remiss not to give a shout-out here to Todd Lewis, chairman of the All Things Open organization, and Jay Zimmerman, director of the No Fluff Just Stuff conferences, for providing me with opportunities to speak and present at their respective conferences over the years. The material in this book is better because of the many presentations I’ve done on related topics in virtual workshops and confer‐ ences for ATO and NFJS since I started learning about Actions. If you ever have a chance to attend one of these conferences or a meetup or virtual event sponsored by these organizations, I encourage you to do so. On a lighter note, thanks to “the gang” (you know who you are), who meet for team building every week at Rally Point (building RP) after work. This is one of the few chances I get to relax while enjoying the conversation and unwinding with people who are not only current and past coworkers, beer aficionados, world philosophers, and technical gurus, but also friends. Most importantly, I want to thank my wife, Anne-Marie, for being my soulmate and always supporting me in everything I do. Through her and our kids, Walker, Chase, Tanner, and Katie, I am constantly reminded that the people and relationships, espe‐ cially family, that we have in our lives are the most important thing. Everything else is simply a means to an end—or should be—to get the time to make the connections and share experiences with our family and friends. Finally, thanks to you, the reader, for getting this book and reading it. I sincerely hope that you will find it useful and something that helps you achieve the goals that you’re looking for as you start or continue your journey with GitHub Actions. xx | Preface
  • 29. CHAPTER 1 The Basics Welcome to Learning GitHub Actions. I’m excited that you’re here and for all that you’re about to learn. This is an amazing time to be working in the software field. From containers to clusters to clouds, from automation to generative AI, from secu‐ rity to SREs, the opportunities to create and contribute to interesting software projects has never been greater. And thanks to powerful platforms such as GitHub, that creation and contribution has never been easier to do. GitHub has led the field in developing an ecosystem for managing the components of software and enabling collaboration, as witnessed by the vast number of open-source projects managed in its repositories. And it has continually provided additional value for users through enhancements to its interfaces, tracking contributions and issues, mechanisms to publish and share information, and much more. For the last decade or slightly longer, creating software effectively has not just been about writing the code. It has been (and is) also about better and faster delivery tech‐ nologies. The capabilities of continuous integration/continuous delivery (aka CI/CD), DevOps, and related practices are now largely taken for granted and easy to achieve. But historically with GitHub, you still needed to do some amount of integration with a separate tool to provide a delivery pipeline or other significant automation. While there have long been ways to bolt on extended CI/CD processes, GitHub has been missing a truly integrated solution to enable CI/CD and an end-to-end software development lifecycle (SDLC) within its ecosystem. The answer to that has now arrived in the form of GitHub Actions. So how does GitHub Actions achieve this? How does it provide real value on its own and over other solutions? And, probably most important to you, how do you easily learn it and start to use it for your own needs? 3
  • 30. When you’re learning a new technology, it’s important (or at least helpful) to have some basic context before diving into the technical details. So in this chapter, I’ll briefly cover some basic information around the following questions: • What are GitHub Actions? • What are the use cases for GitHub Actions? • What are the costs involved? • When does moving to GitHub Actions make sense? By the end of this chapter, you’ll have a solid context to frame the rest of your learn‐ ing on GitHub Actions. Now, let’s get started. Prereqs This book assumes you already have a basic knowledge of Git and GitHub. If that’s not the case, there are a number of free resources to help you understand both. If you already have a cursory knowledge of GitHub Actions, you can skip to Chapter 2 to start diving in on more technical details. But if you’re new to the technology or need to be able to make an informed decision about whether it makes sense for your project or team, I recommend reading the material here. What Is GitHub Actions? You can define GitHub Actions this way: GitHub Actions is an end-to-end GitHub- centric SDLC process. It provides an automation platform and framework that has been missing from GitHub previously and has had to be added on with other solu‐ tions such as Jenkins or Travis CI. There’s a lot packed into that one statement. But let’s key in on two parts that are at the heart of the functionality: automation platform and framework. Automation Platform For purposes of the end user, GitHub Actions is a way to create and execute automa‐ ted workflows tied to GitHub events. Most commonly, you might think of this in the context of CI/CD. As an example, you make a change via a pull request, and GitHub kicks off a continuous delivery pipeline. Prior to GitHub Actions, you would have needed some external tool or process to respond to a notification from GitHub that the pull request happened and then to process it. And the automation that happened after the pull request and initial notification would have been implemented via that external tool. 4 | Chapter 1: The Basics
  • 31. With Actions, you now have the means to create this automation within a context managed by, and within, GitHub. You can define the what, when, and how for auto‐ mated responses to events such as pushes or pull requests. For example, when a push happens in a branch of your repository, automatically grab the latest code and attempt to build it. If a pull request happens for a different branch, automatically build and test the code. If that results in a failure, update a GitHub issue. If there’s not a failure, automatically proceed with putting out a new release. Conveniently, you can create and store your automation definitions and workflows alongside your code in the GitHub repository. And you can edit them there as well. In short, actions make it easier to automate within GitHub because they are a part of GitHub. They are based in a GitHub-provided framework that adds structure and flow. I’ll discuss that next. Framework Taking an automation platform from a jumbled collection of mechanisms to an organized and consumable process requires imposing structure and flow. Without them, you simply have a collection of tools. With them, you can assemble truly useful automation to accomplish whatever set of tasks needs to be done. For Actions, this framework is composed of a core set of related components in Git‐ Hub. These components can be put together to execute simple or complex automa‐ tion in an understandable and predictable way. And this automation is stored in the repository as code. I’ll be talking more about these individual components in Chapter 2. But for a quick overview, it works like this: In response to an occurrence of a matching event, a work‐ flow definition stored within the repository is triggered, which in turn fires off jobs on designated systems called runners. The jobs are made up of sequences of steps that either invoke a predefined action or run a command on the runner’s OS shell. While similar capabilities were available previously in GitHub via mechanisms such as API calls, they were not as easy to assemble at a higher level. Developers often had to invest considerable time and effort to learn how to string together the right API calls and/or integrations with other external tooling (such as Jenkins, Travis CI, etc.). Or they would use custom scripting and programming to be able to get to the desired end goal. This was especially true if they wanted to be able to manage processes through GitHub. (Another workaround was to mirror the repository outside of Git‐ Hub for products to use.) Actions implements a native framework in GitHub providing a more seamless and flexible experience. This flexibility is enhanced by the Actions Marketplace, a public registry where actions can be published and shared. If you want to create workflows to do common activities (such as checking out code or building with a particular What Is GitHub Actions? | 5
  • 32. build tool), you can choose from existing actions in the marketplace. If you want or need more extensive logic, for which an action doesn’t already exist, you can code your own custom action using a well-defined structure. Then you can publish and share it with others via the Marketplace if desired. This approach provides a measure of flexibility, reusability, and extensibility not previously available with GitHub. A sec‐ ondary benefit is that it can enable rapid prototyping and implementation through combining actions for various use cases. I’ll talk about those topics in the next sec‐ tion. Actions versus actions You may notice that at times the term actions is capitalized and other times it is not. This is because there is both the larger frame‐ work/platform to talk about and also the smaller, predefined pieces of functionality. Both of these are referred to with the same term. Following a recommendation from GitHub, I’ll refer to the larger platform/framework as GitHub Actions or Actions (uppercase “A”) and the individual units of functionality as actions (lowercase “a”). What Are the Use Cases for GitHub Actions? When CI/CD first came on the scene, dedicated tools such as Jenkins were the pri‐ mary means of creating pipelines. These tools were flexible—arguably, too flexible. You had to work hard to tie together individual parts into a pipeline. Gradually, with the widespread adoption of CI/CD, the concept of pipelines has come into its own as a predefined structure. And so too has the ability to define pipelines that go beyond just the basics of building simple tests. Today’s CI/CD pipelines can be very complex and can include advanced testing, multiple integration levels, and automated deploy‐ ments/releases. GitHub Actions allows you to create workflows as complex as needed to handle these types of operations without ever leaving GitHub’s ecosystem. Further, it allows you to create as many different workflows as needed for additional automa‐ tion use cases. While GitHub Actions does not use the term pipeline in its processes, the overall workflow approach it uses is a similar concept. Workflows chain together smaller units of work called jobs. Jobs are what you often might see in other applications as stages, meaning parts of a larger process that perform a distinct and separate function. In fact, if you’re coming from working with another automation tool, you can think of the overall GitHub Actions flow as being a pipeline, meaning some change or event causes a series of automated actions to happen automatically in response. The main use cases would be in response to something happening in GitHub. But there are also ways for workflows to be kicked off by events outside of that environ‐ ment, started on a particular schedule, or even initiated manually through the 6 | Chapter 1: The Basics
  • 33. Actions interface in GitHub. I’ll have more to say about these different ways of initiat‐ ing a workflow in Chapter 2 and also in Chapter 8. While CI or CI/CD is the primary purpose that comes to mind, workflows and actions can be used to automate nearly any process. There are two primary places you can look to get ideas about what actions can be used for: the starter workflows and the Actions Marketplace. Workflows versus actions Just to make sure it’s clear, workflows are the scripts or pipelines that control the flow and sequence of activity in GitHub Actions. The individual actions are the functions that can be called to do targeted tasks from within workflows (like checking out code). Starter Workflows To help users bootstrap using Actions, when you start to create a new workflow, Git‐ Hub will present example starter workflows. Figure 1-1 shows an example. You don’t have to use one of these, but if they suit your purpose or come close to it, you can click the Configure button and be working on a new workflow very quickly. As of the time of this writing, the main categories that have starter workflows are: Deployment A set of example workflows for creating deployable objects (like containers) and then deploying them to various cloud platforms Security Primarily a set of code-scanning workflows using various security platforms and their tools Continuous Integration A large number of workflows that cover the areas of building, testing, and/or publishing for a large number of different programming languages and tools Automation Some simple examples for basic automation, including a hello world type, one that demonstrates how to trigger a workflow manually, and a couple that deal with other GitHub constructs such as pull requests and issues Pages Workflows to package/deploy sites using common tools like Gatsby, Astro, Jekyll, etc. You can drill into the full list and code for the starter workflows at https://github.com/ actions/starter-workflows. What Are the Use Cases for GitHub Actions? | 7
  • 34. Figure 1-1. Starter workflows for use with GitHub Actions Actions Marketplace As opposed to workflows that call actions, you can find a useful set of existing actions to call on the GitHub Marketplace in the Actions section. That’s available at the Git‐ Hub Marketplace. Figure 1-2 shows an example of this area in GitHub. These are fully functional units that you can select from and use in your own work‐ flows. Think of it as being like the plug-ins or other add-on modules that add func‐ tionality in other applications. As you’ll see in a later chapter, you can get to the Actions Marketplace from within the GitHub built-in environment for creating a workflow. You can easily browse and find actions here to save you time and effort versus having to code your own. (Creating your own actions is covered in Chapter 11.) 8 | Chapter 1: The Basics
  • 35. Figure 1-2. GitHub Actions Marketplace As examples of the kinds of functionality you can find, the Marketplace has featured categories for interacting with IDEs, working on localization tasks, doing mobile development, and even working with project management tasks through applications such as JIRA. The actions on the Marketplace can be from GitHub or from other sources, such as individuals, organizations, or companies that want to integrate with Actions. When you’re creating a new workflow, the Actions Marketplace is a great place to find existing actions that may already do what you need, thus saving you the effort of cod‐ ing the functionality otherwise. And they’re also free. In fact, you can get started with GitHub Actions for free. But there are costs associated with certain levels of usage. I’ll cover more details on that in the next section. What Are the Use Cases for GitHub Actions? | 9
  • 36. What Costs Are Involved? One of the first questions that comes to mind when any individual, team, or organi‐ zation starts thinking about migrating to a new technology is the cost. With GitHub Actions, you may simply qualify for the free version. But if not, it’s important to have at least a basic understanding of how the paid model works so you’re not surprised. The Free Model GitHub Actions is free if either or both of the following two conditions are true: • The repositories you use with actions are public. • The systems you execute the actions on (the runners) are your own (rather than using the ones provided by GitHub). That means if you are OK with having your GitHub repositories viewable by every‐ one, or if you can host the systems that will execute the code contained in the steps of the workflow, you can use the technology for free. GitHub will not charge you to use self-hosted runners, but you will be required to install and run the runner application on your own servers. This is needed to allow GitHub Actions to communicate with your servers to execute your workflows. (Run‐ ners, including the process to create your own, are covered in Chapter 5.) If the free model doesn’t fit the way you work, you’ll move into the paid model. The Paid Model Private repositories are ones with restricted access. Enterprise/corporate GitHub cli‐ ents may frequently use this model, either via restricting access on the public GitHub site or by using an in-house or on-cloud GitHub instance restricted for their use. There are two types of items you pay for with GitHub Actions: • Storage: Actions allow you to store artifacts and packages on GitHub’s resources. After a certain point, the amount of storage you’re using for artifacts and pack‐ ages will start to cost you. • Minutes: Actions require processing time on virtual systems. Artifacts and Packages Artifacts refer to objects that you upload or generate through your workflows on GitHub. GitHub Packages are a convenient way to make things like containers and dependencies accessible. 10 | Chapter 1: The Basics
  • 37. For a private repository, you start with a certain amount of storage (for artifacts uploaded during processing of workflows) and minutes on runners that are free. After those are used up, you may be able to pay for and use more, or you may be cut off, depending on how you’re paying/billed by GitHub and the defaults for spending limits you have set up. (Artifacts are discussed in more detail in Chapter 7.) If you’re paying/billed a regular amount monthly, after you’ve used up the free storage and minutes, by default, that’s it. You won’t be able to create new artifacts or do addi‐ tional processing. If, instead, you just get an invoice from GitHub for whatever amount of resources you’ve used during a billing period and pay that variable amount each time, by default you can continue to use (and pay for) more minutes and/or storage without limits. Default Spending Limits Default spending limits are referenced in the preceding discussion. Within GitHub, if you have access and authority to do so, those default spending limits can be changed through the settings for the type of account you have (user, organization, or enterprise). Changing them for an organization or enterprise requires that you are an owner or billing manager. For machine usage on a system provided by GitHub, the compute cost is measured in the minutes you use on the runners. This accumulates as you use more compute but resets to 0 each month. The amount of storage you use accumulates as you store more artifacts but is not reset each month. So you just continue to pay the storage cost as long as you keep the artifacts around on GitHub. Table 1-1 from GitHub’s documentation shows the breakdown of the free minutes and free storage you get per month, depending on your account type. This is current as of the time of this writing and subject to change. Always consult the official docu‐ mentation for the latest pricing information. Table 1-1. GitHub Actions pricing plans Plan Storage Minutes (per month) GitHub Free 500 MB 2,000 GitHub Pro 1 GB 3,000 GitHub Free for Organizations 500 MB 2,000 GitHub Team 2 GB 3,000 GitHub Enterprise Cloud 50 GB 50,000 What Costs Are Involved? | 11
  • 38. The storage usage is calculated for each month based on hourly usage during the month. Usage Rounding For billing calculations, storage usage is rounded up to the nearest megabyte, and minute usage is rounded up to the nearest minute. One other key factor to be aware of is that GitHub Actions charge more for jobs run on a system provided by GitHub if it requires a Windows or macOS system to exe‐ cute. So, in a paid scenario, your cost to use one of those system versus a Linux sys‐ tem gets scaled up and you pay a premium, as shown in Table 1-2. Table 1-2. Cost scaling per OS Operating system Minute multiplier Linux 1 macOS 10 Windows 2 Table 1-3 shows an example of how the per-minute costs would compare for a pro‐ cess run on different kinds of systems (taken from GitHub’s documentation). Table 1-3. Per-minute costs across OS Operating system Per-minute rate (USD) Linux $0.008 macOS $0.08 Windows $0.016 Current Cost Information The information in the preceding tables is current as of the time of this writing and is subject to change. For the latest up-to-date information on costs around GitHub Actions, refer to the GitHub documentation. The price you pay for use is certainly one factor to consider if you’re thinking about moving to GitHub Actions. But it should not be the only one. In the final section of this chapter, I’ll discuss how to decide when moving to GitHub Actions makes sense. 12 | Chapter 1: The Basics
  • 39. When Does Moving to GitHub Actions Make Sense? Aside from price, what other factors are worth considering for moving to and using GitHub Actions? Here are a few that may be helpful. Investment in GitHub By definition, GitHub Actions are tightly bound to the GitHub ecosystem. They can only work when run through GitHub’s engine. So anyone needing to work with Actions will need to be familiar with, and comfortable working with, GitHub as an interface and environment. And, if you are using your own runners to execute workflows and actions, you need to be comfortable with having the runner application installed on your systems. Use of Public Actions As discussed previously, GitHub Actions maintains a Marketplace for contributed actions. As with any public place where you can download components to pull in, you want to be sure that you are aware of what those actions are doing and that they meet your security requirements. In short, the responsibility for fit, purpose, and security when using a public action is yours. Helpful Security Tips Chapter 9 in this book covers security. But GitHub also has tips on securely using actions. See the GitHub documentation for more details. Creating Your Own Actions You have the flexibility to create and use your own actions. There are a couple of dif‐ ferent types, as I discuss in Chapter 11. If you have already invested in creating cus‐ tom functionality another way, you’ll need to learn the action structure and syntax. Then consider how you would either migrate to more action-based approaches or have a workflow invoke your existing functionality if feasible to do so. (Chapter 14 discusses approaches for migration.) Artifact Management GitHub Actions artifact management is convenient for quick, easy storage and shar‐ ing of artifacts. But it is not a package management system like GitHub Packages or Artifactory. There is a built-in retention period, after which artifacts are removed. If this is not suitable for your needs, you’ll need to establish another way to manage artifacts and connect your workflows to it. When Does Moving to GitHub Actions Make Sense? | 13
  • 40. Action Management GitHub Actions provides a framework for creating and using actions to automate nearly anything. If you are in a corporate/enterprise environment, you may not want everyone creating and pulling in actions for shared repositories. Allowing this without proper controls could open security holes. Controls might take the form of making sure the set of actions used are approved and manageable. There should also be a regular update process to ensure any public actions used are kept up to date and use of them is reviewed as needed. If employees are creating actions and sharing them for broader use, some sort of code review and standards should be in place. In short, since actions are written with code based in GitHub repositories, the same kinds of best practices you would use with other repositories in GitHub should also apply. Enforcing Policies for Actions For information on how to set policies within an enterprise or organization, see the Enterprise administrator documentation. In general, the question of how much to invest in, and use, GitHub Actions comes down to how much you or your organization or enterprise want to gain the benefits of the new functionality, can migrate any needed existing functionality, and feel com‐ fortable having your code and automation managed in this environment. Conclusion In this chapter, I’ve introduced GitHub Actions and shared some basic information about what the platform is for, its use cases and costs, and factors to consider when moving to it. GitHub Actions provides a full framework to automate the content you manage in GitHub. If you are invested in the GitHub ecosystem or considering mov‐ ing to it, workflows and actions provide a good option for implementing automation such as CI/CD without having to rely on another application. As with any frame‐ work, the automation can be simple or complex. And while the underlying engine is provided by GitHub, there is an ever-growing community of users providing ready- made actions and workflows to draw on and lessen the setup/custom investment required. Now that the basics of GitHub Actions have been explained, in the next chapter, I’ll dive in more to help you understand how actions work. 14 | Chapter 1: The Basics
  • 41. CHAPTER 2 How Does Actions Work? In Chapter 1, you got acquainted at a high level with the overall framework and value of GitHub Actions. In this chapter, we’ll dive into the parts that make up GitHub Actions and how they work together, meaning what kicks them off, what happens when they run, and so on. As a reminder, in the world of GitHub Actions, actions can refer to the following: • The entire system for executing automated workflows in response to events • The actual units of code and related pieces that implement individual actions Following the convention suggested by GitHub, the book will use GitHub Actions or Actions (with an uppercase “A”) to refer to the system and actions (with a lowercase “a”) to refer to the code units. To better understand the Actions environment, I’ll provide you with an overview of how the overall flow works. This includes the types of events that can start the auto‐ mation and a high-level overview of the components that are involved in the execu‐ tion of the automation. Throughout the chapter, I’ll offer some simple example code. This will give you a solid understanding of how the flow works. An Overview At a high level, the GitHub Actions flow is this: 1. Some triggering event happens in a GitHub repository. This event is most often associated with a unique SHA1 (Secure Hashing Algorithm 1) value and a Git reference that resolves to an SHA1 value (a ref), such as a branch. But it may also be an event in GitHub that is not an update to a ref. An example would be a com‐ ment made in a pull request or an issue being updated. 15
  • 42. 2. A dedicated directory in the repository (.github/workflows) is searched for work‐ flow files that are coded to respond to the event type. Many events can also include additional qualifiers. For example, a workflow can be set up to be trig‐ gered only when a push operation happens on the branch named main. 3. Corresponding workflows are identified, and new runs of the matching work‐ flows are triggered. The workflow object is the key piece here. A GitHub Actions workflow is a set of code that defines a sequence and set of steps to execute, similar to a script or a program. The file itself must be coded in YAML format and stored in the <repository>/.github/ workflows directory. Workflow files have a specific syntax. A workflow contains one or more jobs. Each job can be as simple or as complex as needed. Once a workflow is kicked off, the jobs begin executing. By default, they run in parallel. Jobs, in turn, are made up of steps. A step either runs a shell command or invokes a predefined GitHub action. All of the steps in a job are executed on a runner. The run‐ ner is a server (virtual or physical) or a container that has been set up to understand how to interact with GitHub Actions. I’ll go into more detail on each of these items later, but Figure 2-1 illustrates the basic design. Figure 2-1. Relationship of GitHub Actions components 16 | Chapter 2: How Does Actions Work?
  • 43. If this seems familiar, it’s probably because it’s a CI pattern. Some change is made that is automatically detected and that triggers a set of automated processes to run and respond to the change. In GitHub Actions, the changes that signal that work needs to be kicked off are trig‐ gering events (aka triggers). Triggering Workflows Events trigger workflows. They serve as the signal for work to start happening if a GitHub Actions workflow is present and the triggering event matches the start condi‐ tions specified in the workflow. An event can be defined in several different ways: • A person or a process does some operation in a GitHub repository. • A matching external trigger happens—that is, an event from outside of GitHub. • A schedule is set up to run a workflow at particular times or intervals. • A workflow is initiated manually, without an operation having to be done first. I’ll dive into these different types more in Chapter 3 and extensively in Chapter 8, but an event triggered from an operation in a GitHub repository is probably the most common type. An example of this kind of event is a GitHub pull request. If you or a process initiates a pull request, then a corresponding pull request event is triggered. There is also a push event for code pushes. In GitHub, there are a large number of common operations you can do that can serve as triggers for a workflow. There are also multiple ways to govern when workflows react to the triggers. To understand this, here’s the first piece of workflow syntax to become familiar with— the on clause. The on keyword and the lines that follow it define which types of trig‐ gers the workflow will match on and start executing. Some basic types of triggers and simple examples of the syntax for each follow: The workflow can respond to a single event such as when a push happens: on: push The workflow can respond to a list (multiple events): on: [push, pull_request] The workflow can respond to event types with qualifiers, such as branches, tags, or file paths: on: push: branches: - main - 'rel/v*' Triggering Workflows | 17
  • 44. tags: - v1.* - beta paths: - '**.ts' The workflow can execute on a specific schedule or interval (using standard cron syntax): on: scheduled: - cron: '30 5,15 * * *' @interval Syntax Syntax like @daily, @hourly, and so on is not supported. The workflow can respond to specific manual events (more about these later): on: [workflow-dispatch, repository-dispatch] The workflow can be called from other workflows (referred to as a reuse event): on: workflow_call The workflow can respond to webhook events—that is, when a webhook executes and sends a payload. (See the related documentation for more details on events and pay‐ loads in webhooks.) The workflow can respond to common activities on GitHub items, such as adding a comment to a GitHub issue: on: issue_comment Events That Trigger Only If the Workflow File Exists on the Default Branch Be aware that a subset of less-common events will only trigger a workflow run if the workflow file (the YAML file in .github/workflows) is on the default branch (usually main). For those events, if you have the workflow file only on a non-default branch and you trigger the activity that would normally cause the workflow to run, nothing will happen. You can trigger the event from another branch. But, for these special cases, the work‐ flow file has to exist on the default branch, regardless of which branch the trigger actually happens on. This can present tricky situations when you are trying to develop a workflow in a different branch and prove it prior to doing a pull request. 18 | Chapter 2: How Does Actions Work?
  • 45. To see if an event is one that can only be triggered for the default branch in your repository, go to the documentation and check for a Note section that says, “This event will only trigger a workflow run if the workflow file is on the default branch.” Deciding how you want your workflows to be triggered is one of the first steps to implementing functionality with GitHub Actions. To complete the picture, you need to understand more about the other parts that make up a workflow. I briefly touched on these in Chapter 1, but I’ll explain more about them in the next section. Components I’m using components here as an umbrella term (not an official one), for the major pieces that GitHub Actions defines for you to use to build and execute a workflow. For simplicity, I’ll just do a brief survey of each one to help you understand them from a higher level. Steps Steps are the basic unit of execution you deal with when working with GitHub Actions. They consist of either invocations of a predefined action or a shell command to be run on the runner. Any shell commands are executed via a run clause. And any predefined actions are pulled in via a uses clause. The steps keyword indicates the start of a series of steps to be run sequentially. The code listing that follows shows an example of three basic steps from a workflow. These steps check out a set of code, set up a go environment based on a particular version, and run the go process on a source file. In the YAML syntax, the - character indicates where a step starts. The uses clause indicates that this step invokes a prede‐ fined action. The with clause is used to specify arguments/parameters to pass to the action. And the run clause indicates a command to be run in the shell. Note that steps can have a name associated with them as well: steps: - uses: actions/checkout@v3 - name: setup Go version uses: actions/setup-go@v2 with: go-version: '1.14.0' - run: go run helloworld.go Components | 19
  • 46. Runners Runners are the physical or virtual computers or containers where the code for a workflow is executed. They can be systems provided and hosted by GitHub (and run within their control), or they can be instances you set up, host, and control. In either case, the systems are configured to understand how to interact with the GitHub Actions framework. This mean they can interact with GitHub to access workflows and predefined actions, execute steps, and report outcomes. In a workflow file, runners are defined for jobs simply via the runs-on clause. (Run‐ ners are discussed in more detail in Chapter 5.) runs-on: ubuntu-latest Jobs Jobs aggregate steps and define which runner to execute them on. An individual job is usually targeted towards accomplishing one particular goal of the overall workflow. An example could be a workflow that implements a CI/CD pipeline with separate jobs for building, testing, and packaging. Aside from the definition of the runner, a job in a workflow is like a function or pro‐ cedure in a programming language. It is made up of a series of individual commands to run and/or predefined actions to call. This is similar to how a function or proce‐ dure in a programming language is made of individual lines of code and/or calls to other functions or procedures. The outcome of the job is surfaced in the GitHub Actions interfaces. Success or fail‐ ure is displayed at the level of the job, not the individual steps. It’s helpful to keep this success/failure status at the job level in mind when determining how much work you want any individual job to do. It’s also helpful when considering how much detail you want to know about success or failure within the workflow execution without having to drill down. If you need more granular reports of success or failure displayed at the top level, you may want to put fewer steps in a job. Or, if you need less-granular indications of whether a set of steps succeeded or failed, you might put more steps into a job. Building on the steps and runners previously shown, the next listing shows a simple job that does the checkout and setup and performs a build: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: setup Go version' uses: actions/setup-go@v2 20 | Chapter 2: How Does Actions Work?
  • 47. with: go-version: '1.14.0' - run: go run helloworld.go Workflow A workflow is like a pipeline. At a high level, it first defines the types of inputs (events) that it will respond to and under what conditions it will respond to them. This is what we talked about in the earlier section on events. The response, if the events and conditions match, is to then execute the series of jobs in the workflow, which, in turn, execute the steps for each job. The overall flow is like a continuous integration process in that it responds to a par‐ ticular kind of change and kicks off an automated sequence of work. The next listing shows an example of a simple workflow for processing Go programs built on the pre‐ vious definitions: 1. name: Simple Go Build 2. 3. on: 4. push: 5. branches: 6. - main 7. 8. jobs: 9. build: 10. runs-on: ubuntu-latest 11. steps: 12. - uses: actions/checkout@v3 13. - name: Setup Go version 14. uses: actions/setup-go@v2 15. with: 16. go-version: '1.15.1' 17. - run: go run hello-world.go Note that this workflow is written in YAML format. I’ll break down what’s happening in this file, line by line: Line 1: The workflow file is assigned a name. Line 3: This is the on identifier discussed in the section on events. Lines 4–6: This workflow is triggered when a push operation is done to the branch main in this GitHub repository. Line 8: This starts the jobs portion of the workflow. Line 9: There is one job in this workflow, named build. Line 10: This job will be executed on a runner system, hosted by GitHub, provisioned with a standard ubuntu operating system image. Components | 21
  • 48. Line 11: This starts the series of steps for this job. Line 12: The first step is done via pulling in a predefined action. Note the way this is referenced. actions/checkout@v3 refers to the relative path after github.com, so this really says it is going to run/use the action defined at github.com/actions/checkout. Also notice that this is the only line in this step—no parameters need to be passed to this action because it assumes it is checking out the source from this repository since it is in this repository. Line 13: The hyphen at the start of this line indicates this is the start of a second step. This line is giving the new step a name. Line 14: The same step is pulling in another predefined action to set up the Go envi‐ ronment. Lines 15–16: The setup-go action needs a parameter—the version of Go to use. The parameter is passed as an input to the action via a with clause. Line 17: This is another step, one that simply runs a command as indicated by the run keyword. The command is to execute the go run command on an example file in the repository. As a reminder, in order to be found, matched to event conditions, and executed auto‐ matically, this code needs to be stored in a YAML file in a special directory in a Git‐ Hub repository: .github/workflows. As an example, you could save the preceding code in <your repository>/.github/workflows/simple-go-build.yml. (Note the file extension here needs to be either .yml or .yaml, denoting YAML structure and syntax.) Workflow Execution If you push the .github/workflows/simple-go-build.yml file and a corresponding hello- world.go file to a GitHub repository, you can see the workflow actually run right away. This is because the event condition set in the workflow (on a push to main) would match. So the workflow would be triggered and executed as soon as it is pushed. GitHub repositories contain an Actions selection at the top of the project page. Select‐ ing this puts you into a graphical interface where you can see runs of workflows and jobs. After pushing the workflow file, if you select the Actions tab at the top, you will see the execution of your simple workflow, as shown in the example in Figure 2-2. 22 | Chapter 2: How Does Actions Work?
  • 49. Figure 2-2. Workflow run From here, you can select a run of a workflow and see the jobs that ran as part of the workflow and their statuses. Figure 2-3 shows the execution of the job from our sim‐ ple workflow. Figure 2-3. Run at the job level Workflow Execution | 23
  • 50. In later chapters, you’ll see how to use this interface to drill in further to what occurs when the various steps are executed and how to debug problems, when actions run, using the interface. Conclusion Actions can refer to either the code that implements an action, the automated envi‐ ronment for defining and running those actions as part of a workflow, or both. In this chapter, I’ve focused on understanding the workflow, its components, and the way it is executed. Workflows are like software pipelines. They can be initiated when a triggering event occurs (like continuous integration), and they aggregate one or more jobs to accom‐ plish their overall task. Each job in turn aggregates one or more steps to do smaller units of work. The execution of the steps in a single job results in a success/failure outcome for the job, which feeds back into success/failure for the overall workflow. Each job declares what kind of runner system (operating system and version) it will run in. And, at the lowest level, steps can invoke predefined GitHub Actions or run simple commands on that system. Now that you have a basic understanding of how workflows work within GitHub Actions, Chapter 3 will give you a similar understanding of how individual actions work. 24 | Chapter 2: How Does Actions Work?
  • 51. CHAPTER 3 What’s in an action? In Chapter 2, we explored how GitHub Actions does its processing. The core func‐ tionality centers around workflows—the code that runs in response to an event and executes jobs to do some work. At the lowest level in your workflow, the workflow’s jobs execute steps. And steps can call either an OS command or an implementation of separate functionality that GitHub Actions simply refers to as an action. Workflows versus actions Since the distinction between actions and workflows can be one of the points that remains confusing for a while, here’s a reminder to think of actions as being like plug-ins or modules in other applica‐ tions and the workflows as being more like the pipelines or scripts that use those modules or plug-ins. You have the background now to understand where the implementation of an actual action is used—when a step in a workflow calls it. In this chapter, I’ll continue the broad overview of the GitHub Actions platform by looking at what makes up an indi‐ vidual action. Specifically, I’ll discuss the following: • The structure of an action • Interfacing with actions • Using actions • Public actions and the Actions Marketplace 25
  • 52. Implementation of an action Note that this chapter does not describe how to create a new action. Chapter 11 goes into detail on how to create your own custom action. The Structure of an action The implementation of an action can range from very simple to very complex. On the simple side, it might be a small shell script that gets executed. On the complex end, it may be a large set of implementation code, test cases, and workflows to handle CI/CD tasks like validating content, building, checking for vulnerabilities, packaging, and so on. The checkout action referenced in Chapter 2 is one such implementation on the com‐ plex end of that range. Figure 3-1 shows part of the main page for the GitHub reposi‐ tory behind that action. Figure 3-1. Checkout action in GitHub 26 | Chapter 3: What’s in an action?
  • 53. Underlying each action is a code base in a GitHub repository. Like many other projects in GitHub, this repository has a lot of supporting pieces in addition to the code (licensing, tests, source, .gitattributes, etc.) If you drill into the src area, you can see more of the underlying implementation, including the TypeScript files (.ts exten‐ sion) that do the real work. Figure 3-2 shows the contents of the src subdirectory. Figure 3-2. src directory in checkout action On the main page, you can also see references to the contributors, the README file, and other typical information such as the language breakdown and the usage infor‐ mation. (Note that, as a testament to the use of actions, the checkout action has nearly 4 million used by references, as shown in Figure 3-3.) The Structure of an action | 27
  • 54. Figure 3-3. Additional info on action page This action also has a supporting set of workflow files. Like any other workflows, these are stored in the .github/workflows subdirectory of the repository. In the case of the checkout action, the files help to validate content being updated in the repository. They are set up to respond to events such as pushes and pull requests. The set of workflows associated with this action is shown in Figure 3-4. So workflows use actions to do work in steps, and actions use workflows for CI/CD, automation, validation, etc. From this, you can start to see how the parts of GitHub Actions can work together at a broader level. The key part of a project in GitHub that allows it to be used as an action is a special file that designates it as an action. This file also describes the action’s key characteris‐ tics, such as the inputs it can have. I’ll discuss this file in the next section. 28 | Chapter 3: What’s in an action?
  • 55. Random documents with unrelated content Scribd suggests to you:
  • 56. course I am glad that the man is not badly hurt. Still, a few shot in the arm will hardly keep him in bounds. His legs were intended,” she laughed lightly. “What miserable aim Tompkins must take.” “He's a bit off in his physiology, my dear,” said Cecil, with a nervous attempt at humour. He did not like the expression in his sister's face. Somehow, he was ashamed. “Oh, it's bad enough,” said Penelope. “It was his left arm—the upper arm, too. I think the aim was rather good.” “Pray, how do you know all of this, Penelope?” asked her ladyship, lifting her eyebrows. “I 've heard that you see Mr. Shaw occasionally, but you can't be his physician, I'm sure.” Penelope flushed to the roots of her hair, but suppressed the retort which would have been in keeping with the provocation. “Oh, dear, no!” she replied. “I'm too soft-hearted to be a physician. I saw Mr. Shaw just after the—ah—the incident.” “You shaw Saw—I mean you saw Shaw?” gasped Bazelhurst. “She sees him frequently, Cecil. It was not at all unusual that she should have seen him to-day. I daresay he waited to show you his wound before going to a surgeon.” Penelope could not resist the temptation to invent a story befitting the moment. Assuming a look of concern, she turned to her brother and said: “He is coming to see you about it to-morrow, and he is coming armed to the teeth, attended by a large party of friends. Mr. Shaw says he will have satisfaction for the death of that dog if he has to shoot everybody on the place.” “Good Lord!” cried the duke. There was instant excitement. “I believe the wretch will do it, too.” “Oh, I say, Bazelhurst, settle with him for the dog,” said De Peyton nervously. He looked at his watch and then at his wife. The entire party now was listening to the principal speakers.
  • 57. “Nonsense!” exclaimed Lady Evelyn. “He won't come. It's all bluster. Don't let it frighten you, Cecil. I know the manner of man.” “I wish you could have seen him this morning,” murmured Penelope, thoroughly enjoying the unexpected situation. Her conscience was not troubled by the prevarication. “By Jove, I think it would be wise to send over and find out what he valued the brute at,” said Cecil, mopping his brow. “Good. We'll send Penelope to act as ambassador,” said her ladyship. “She seems to be on friendly terms with the enemy.” “To act as ambassador from Cowardice Court?” questioned Penelope, loftily, yet with cutting significance. “No, I thank you. I decline the honour. Besides,” with a reflective frown, “I don't believe it is diplomacy he's after.” “I say what the deuce do you suppose the confounded savage has in mind?” exclaimed the duke. “I 'Ve heard of the way these cowboys settle their affairs. You don't imagine—” and he paused significantly. “It looks like it's going to be a da—rather disagreeable affair,” said De Peyton sourly. “Good heavens, what are we to do if he comes here with a lot of desperadoes and begins to shoot?” cried Mrs. Odwell, genuinely alarmed. “I've read so much of these awful mountain feuds.” “Don't be alarmed. Lord Bazelhurst will attend to the gentleman,” said Lady Evelyn blandly. His lordship's monocle clattered down and the ice rattled sharply in his glass. “To—to be sure,” he agreed. “Don't be in the least worried. I 'll attend to the upstart. What time's he coming, Pen?” A door banged noisily near by, and every one jumped as though a gun had been fired. While the “ohs” were still struggling from their lips, Hodder, the butler, came into the room, doing his best to retain his composure under what seemed to be trying circumstances. “What is it, Hodder?” demanded her ladyship.
  • 58. “The cook, your ladyship. She's fallen downstairs and broken her leg,” announced Hodder. He did not betray it, but he must have been tremendously surprised by the sigh of relief that went up on all sides. Lord Bazelhurst went so far as to laugh. “Ha, ha! is that all?” “Oh, dear, I'm so glad!” cried Miss Folsom, impulsively. “I was frightened half to death. It might have been Mr.—” “Don't be silly, Rose,” said Lady Bazelhurst. “Where is she, Hodder?” “In the laundry, your ladyship. There are two fractures.” “By Jove, two legs instead of one, then—worse than I thought,” cried Bazelhurst, draining his glass. “Send at once for a doctor, Hodder, and take her to her room. Is n't it annoying,” said her ladyship. “It's so difficult to keep a cook in the mountains.” “Don't see how she can get away without legs,” observed De Peyton. “I'll come with you, Hodder. Perhaps I can do something for her,” said Penelope, following the butler from the room. “Don't take too many patients on your hands, my dear,” called the mistress, with a shrill laugh. “Yes; remember to-morrow,” added the duke. Then, suddenly: “I believe I'll lend a hand.” He hurried after Penelope, rather actively for him. Lord Bazelhurst visited his wife's room later in the night, called there by a more or les: peremptory summons. Cecil had been taking time by the forelock in anticipation of Shaw's descent in the morning and was inclined to jocundity. “Cecil, what do you think of Penelope's attitude toward Mr. Shaw?” she asked, turning away from the window which looked out over the night in the direction of Shaw's place.
  • 59. “I didn't know she had an attitude,” replied he, trying to focus his wavering gaze upon her. “She meets him clandestinely and she supports him openly. Is n't that an attitude, or are you too drunk to see it?” “My dear, remember you are speaking of my sister,” he said with fine dignity but little discrimination. “Besides, I am not too drunk. I do see it. It's a demmed annoying attitude. She 's a traitor, un'stand me? A traito-tor. I intend to speak to her about it.” “It is better that you should do it,” said his wife. “I am afraid I could not control my temper.” “Penelope's a disgrace—a nabsolute disgrace; now many legs did Hodder say—” “Oh, you're disgusting!” cried Lady Evelyn. “Go to bed! I thought I could talk to you to-night, but I can't. You scarcely can stand up.” “Now, Evelyn, you do me injustice. I'm only holding to this chair to keep it from moving 'round the room. See that? Course I c'n stan' up,” he cried, triumphantly. “I am utterly disgusted with you. Oh, for a man! A man with real blood in his veins, a man who could do something besides eat and drink at my cost. I pay your debts, clothe you, feed you—house your ungrateful sister—and what do I get in return? This!” Lord Bazelhurst's eyes steadied beneath this unexpected assault, his legs stiffened, his shoulders squared themselves in a pitiful attempt at dignity. “Lady Bazelhurst, you—you—” and then he collapsed into the chair, bursting into maudlin tears. She stood over by the dressing- table and looked pitilessly upon the weak creature whose hiccoughing sobs filled the room. Her colour was high, her breathing heavy. In some way it seemed as though there was so much more she could have said had the circumstances been different.
  • 60. There came a knock at the door, but she did not respond. Then the door opened quietly and Penelope entered the room, resolutely, fearlessly. Evelyn turned her eyes upon the intruder and stared for a moment. “Did you knock?” she asked at last. “Yes. You did not answer.” “Was n't that sufficient?” “Not to-night, Evelyn. I came to have it out with you and Cecil. Where is he?” “There!” “Asleep?” with a look of amazement. “I hope not. I should dislike having to call the servants to carry him to his see. Poor old chap!” She went over and shook him by the shoulder. He sat up and stared at her blankly through his drenched eyes. Then, as if the occasion called for a supreme effort, he tried to rise, ashamed that his sister should have found him in his present condition. “Don't get up, Cecil. Wait a bit and I'll go to your—” “What have you to say to me, Penelope,” demanded Evelyn, a green light in her eyes. “It can wait. I prefer to have Cecil—understand,” she said, bitterly. “If it 's about our affair with Shaw, it won't make any difference whether Cecil understands or not. Has your friend asked you to plead for him? Does he expect me to take him up on your account and have him here?” “I was jesting when I said he would come to-morrow,” said Penelope, ignoring the thrust and hurrying to her subject. “I could n't go to sleep to-night if I neglected to tell you what I think of the outrage this morning. You and Cecil had no right to order Tompkins to shoot at Mr. Shaw. He is not a trespasser. Some one killed his dog to-day. When he pursued the coward, a second shot was fired at him. He was wounded. Do you call that fair fighting? Ambushed,
  • 61. shot from behind a tree. I don't care what you and Cecil think about it, I consider it despicable. Thank God, Cecil was not really to blame. It is about the only thing I can say to my brother's credit.” Lady Bazelhurst was staring at her young sister-in-law with wide eyes. It was the first time in all her petted, vain life that any one had called her to account. She was, at first, too deeply amazed to resent the sharp attack. “Penelope Drake!” was all she could say. Then the fury in her soul began to search for an outlet. “How dare you? How dare you?” “I don't mean to hurt you, I am only telling you that your way of treating this affair is a mistake. It can be rectified. You don't want to be lawless; you don't understand what a narrow escape from murder you have had. Evelyn, you owe reparation to Mr. Shaw. He is—” “I understand why you take his side. You cheapen and degrade yourself and you bring shame upon your brother and me by your disgraceful affair with this ruffian. Don't look shocked! You meet him secretly, I know—how much farther you have gone with him I don't know. It is enough that you—” “Stop! You shall not say such things to me!” “You came in here to have it out with me. Weil, we'll have it out. You think because you're English, and all that, that you are better than I. You show it in your every action; you turn up your nose at me because I am an American. Well, what if I am? Where would you be if it were not for me? And where would he be? You'd starve if it were not for me. You hang to me like a leech—you sponge on me, you gorge yourself—” “That is enough, Evelyn. You have said all that is necessary. I deserve it, too, for meddling in your affairs. It may satisfy you to know that I have always despised you. Having confessed, I can only add that we cannot live another hour under the same roof. You need not order me to go. I shall do so of my own accord—gladly.” Penelope turned to the door. She was as cold as ice.
  • 62. “It is the first time you have ever done anything to please me. You may go in the morning.” “I shall go to-night!” “As you like. It is near morning. Where do you expect to go at this hour of night?” “I am not afraid of the night. Tomorrow I shall send over from the village for my trunks.” She paused near the door and then came back to Cecil's side. “Goodbye, Cecil. I'll write. Good-bye.” He looked up with a hazy smile. “G'night,” he muttered thickly. Without another word or so much as a glance at Lady Bazelhurst, Penelope Drake went swiftly from the room. The big hall clock struck the half-hour after eleven. Some one—a woman—was laughing in the billiard-room below; the click of the balls came to her ears like the snapping of angry teeth. She did not hesitate; it was not in her nature. The room in which she had found so much delight was now loathsome to her. With nervous fingers she threw the small things she most cherished into a bag,—her purse, her jewels, her little treasures. Somehow it seemed to her as if she were hurrying to catch a night train, that was all. With her own strong young arms she dragged the two huge trunks from the closet. Half an hour later they were full and locked. Then she looked about with a dry, mirthless smile. “I wonder where I am to go?” she murmured, half aloud. A momentary feeling of indecision attacked her. The click of the balls had ceased, the clock had struck twelve. It was dark and still, and the wind was crying in the trees. “She won't go,” Lady Bazelhurst was saying to herself, as she sat, narrow-eyed and hateful, in her window looking out into the night. “Life is too easy here.” The light from the porch lanterns cast a feeble glow out beyond the porte-cochère and down the drive. As she stared across the circle, the figure of a woman suddenly cut a diametric line through it, and lost itself in the wall of blackness that
  • 63. formed the circumference. Lady Evelyn started and stared unbelievingly into the darkness, striving to penetrate it with her gaze. “It was she—Penelope,” she cried, coming to her feet. “She's really gone—she meant it.” For many minutes she peered out into the night, expecting to see the shadow returning. A touch of anxious hope possessing her, she left the window and hurried down the corridor to Penelope's room. What she found there was most convincing. It was not a trick of the lanterns. The shadow had been real. It must be confessed that the peevish heart of Lady Bazelhurst beat rather rapidly as she hastened back to the window to peer anxiously out into the sombre park with its hooting owls and chattering night-bugs. The mournful yelp of a distant dog floated across the black valley. The watcher shuddered as she recalled stories of panthers that had infested the great hills. A small feeling of shame and regret began to develop with annoying insistence. An hour dragged itself by before she arose petulantly, half terrified, half annoyed in spite of herself. Her husband still was sitting in the big chair, his face in his hands. His small, dejected figure appealed to her pity for the first time in the two years of their association. She realized what her temper had compelled her to say to him and to his sister; she saw the insults that at least one of them had come to resent. “I hope that foolish girl will come back,” she found herself saying, with a troubled look from the window. “Where can the poor thing go? What will become of her? What will everyone say when this becomes known?” she cried, with fresh selfishness. “I—I should not have let her go like this.” Even as she reproached herself, a light broke in upon her understanding; a thought whirled into her brain and a moment later she knew where she could go! “How simple I am. Shaw will welcome her gladly. She's with him by this time—his doors have opened to her. The little wretch! And I've been trying so hard to pity her!” She laughed again so shrilly that his lordship stirred and then looked up at her stupefied, uncertain.
  • 64. “Hullo,” he grunted. “What time is it?” “Oh, you're awake, are you?” scornfully. “Certainly. Have I been dozing? What's there to laugh at, my dear?” he mumbled, arising very unsteadily. “Where's Pen?” “She's gone. She's left the house,” she said, recurring dread and anxiety in her voice. A glance at the darkness outside brought back the growing shudders. “What—what d' ye mean?” demanded he, bracing up with a splendid effort. “She's left the house, that's all. We quarrelled. I don't know where she's gone. Yes, I do know. She's gone to Shaw's for the night. She's with him. I saw her going,” she cried, striving between fear and anger. “You 've—you've turned her out? Good Lord, why—why did you let her go?” He turned and rushed toward the door, tears springing to his eyes. He was sobering now and the tears were wrenched from his hurt pride. “How long ago?” “An hour or more. She went of her own accord. You'll find her at Shaw's,” said her ladyship harshly. She hated to admit that she was to blame. But as her husband left the room, banging the door after him, she caught her breath several times in a futile effort to stay the sobs, and then broke down and cried, a very much abused young woman. She hated everybody and everything.
  • 65. L CHAPTER V—IN WHICH DAN CUPID TRESPASSES ADY BAZELHURST was right. Penelope was making her way through the blackest of nights toward the home of Randolph Shaw. In deciding upon this step, after long deliberation, she had said to herself: “Randolph Shaw is the only real man I 've seen since coming to the mountains. I can trust him to help me to-night.” It was fully three miles to Shaw's place, most of the way over the narrow valley road. She knew she would encounter but few tortuous places. The last half-mile, however, was steep, rugged, and unfamiliar to her. She had ventured no nearer to his home than Renwood's deserted cottage, lying above and to the south of the road, almost at the base of the long hill on whose side Shaw had built his big home. To climb that hill was no easy task in daylight; at midnight, with the stars obscured by clouds and tree-tops, there was something perilously uncertain in the prospect. Only the knowledge that patience and courage eventually would bring her to the end made the journey possible. Time would lead her to the haven; care would make the road a friend; a stout heart was her best ally. Strength of limb and strength of purpose she had, in use and in reserve. No power could have made her turn back willingly. Her anxious eyes were set ahead in the blackness; her runaway feet were eager in obedience to her will. “Why couldn't I have put it off until morning?” she was saying to herself as she passed down the gravelled drive and advanced to meet the wall of trees that frowned blackly in her face. “What will he think? What will he say? Oh, he'll think I'm such a silly, romantic fool. No, he won't. He'll understand. He'll help me on to Platts-burg to-morrow. But will he think I've done this for effect? Won't he think
  • 66. I'm actually throwing myself at his head? No, I can't turn back. I'd rather die than go back to that house. It won't matter what he thinks; I'll be away from all of it tomorrow. I'll be out of his life and I won't care what he thinks. England! Goodness, what's that?” She had turned a bend in the drive and just ahead there was a light. A sigh of relief followed the question. It came from the lantern which hung to a stake in the road where the new stone gate-posts were being built by workmen from town. Bazelhurst Villa was a quarter of a mile, through the park, behind her; the forest was ahead. At the gate she stopped between the half-finished stone posts and looked ahead with the first shiver of dismay. Her limbs seemed ready to collapse. The flush of anger and excitement left her face; a white, desolate look came in its stead. Her eyes grew wide and she blinked her lashes with an awed uncertainty that boded ill for the stability of her adventure. An owl hooted in mournful cadence close by and she felt that her hair was going straight on end. The tense fingers of one hand gripped the handle of the travelling-bag while the other went spasmodically to her heart. “Oh!” she gasped, moving over quickly to the stake on which the lantern hung. The wind was rushing through the tree-tops with increased fervour; the air was cool and wet with the signs of rain; a swirl of dust flew up into her face; the swish of leaves sounded like the splashing of water in the air. Holding her heart for minutes, she at last regained some of the lost composure. A hysterical laugh fell from her lips. “What a goose! It was an owl and I've heard hundreds of them up here. Still, they do sound different outside of one's own room. It's going to rain. What wretched luck! Dear me, I can't stand here all night. How black it is ahead there. Oooh! Really, now, it does seem a bit terrifying. If I only had a lantern it would n't be so —” her gaze fell upon the labourers' lantern that clattered aimlessly, uselessly against the stake. An instant later she had jerked it from its fastenings with a cry of joy. “I'll send it back when they go for my trunks. What luck!”
  • 67. Without a second's hesitation she started off briskly into the woodland road, striding along with the splendid swing of the healthy Englishwoman who has not been trained to dawdle. Her walking- skirt gave free play to her limbs; she was far past the well-known “line in the road” before she paused to take a full breath and to recapitulate. Her heart beat faster and the sudden glow in her cheek was not from the exercise. Somehow, out there alone in the world, the most amazing feeling of tenderness sped on ahead to Randolph Shaw. She tried to put it from her, but it grew and grew. Then she blushed deep within herself and her eyes grew sweet with the memory of those stolen, reprehensible hours along the frontier. Something within her breast cried out for those shining, gone-by moments, something seemed to close down on her throat, something flooded her eyes with a softness that rolled up from her entire being. Their line! Their insurmountable barrier! An absurd yet ineffable longing to fall down and kiss that line came over her with compelling force. Her head grew light with the thought of those moments when their horses stood with muzzles together as if kissing by proxy—the flush grew deeper, though her blood went cold and she trembled. A pitiful confusion seized her, an inexplicable timidity crept into her heart, replacing the bold assurance that had been recklessly carrying her on to him. It was as though some one had whispered the truth into her ear and she was beginning to believe. From that moment her courage began to fail. The glow from her lantern was a menace instead of a help. A sweet timorousness enveloped her and something tingled—she knew not what. Spattering raindrops whizzed in her face, ominous forerunners from the inky sky. The wind was whistling with shrill glee in the tree- tops and the tree-tops tried to flee before it. A mile and a half lay between her and the big cottage on the hillside—the most arduous part of the journey by far. She walked and ran as though pursued, scudding over the road with a swiftness that would have amazed
  • 68. another, but which seemed the essence of slowness to her. Thoughts of robbers, tramps, wild beasts, assailed her with intermittent terrors, but all served to diminish the feeling of shyness that had been interfering with her determination. Past Renwood's cottage she sped, shuddering as she recognized the stone steps and path that ran up the hillside to the haunted house. Ghosts, witches, hobgoblins fell into the procession of pursuers, cheered on by the shrieking wind that grew more noisome as her feet carried her higher up the mountain. Now she was on new ground. She had never before explored so far as this. The hill was steep and the road had black abysses out beyond its edges.... She was breathless, half dead from fatigue and terror when at last her feet stumbled up the broad steps leading to his porch. Trembling, she sank into the rustic bench that stood against the wall. The lantern clattered to her feet, and the bag with her jewels, her letter of credit, and her curling irons slid to the floor behind the bench. Here was his home! What cared she for the storm? Even as she lay there gasping for breath, her eyes on the shadowy moon that was breaking its way through the clouds, three men raced from the stables at Bazelhurst Villa bent on finding the mad young person who had fled the place. Scarcely knowing what direction he took, Lord Bazelhurst led the way, followed by the duke and the count, all of them supplied with carriage lamps, which, at any other time, would have been sickening in their obtrusiveness. Except for Lady Evelyn, the rest of the house slept the sleep of ease. Gradually Penelope recovered from the effects of the mad race up the hill. The sputtering flame in the lantern called her into action. Clutching it from the floor of the porch, she softly began a tour of inspection, first looking at her watch to find that it was the unholy hour of two! Had some one yelled boo! she would have swooned, so tense was every nerve. Now that she was here, what was she to do? Her heart came to her mouth, her hand shook, but not with fear; a nervous smile tried to wreak disaster to the concern in her eyes.
  • 69. The house was dark and still. No one was stirring. The porch was littered with rugs and cushions, while on a small table near the end stood a decanter, a siphon, and two glasses. Two? He had said he was alone except for the housekeeper and the servants. A visitor, then. This was not what she had expected. Her heart sank. It would be hard to face the master of the house, but—a stranger? Cigarette stubs met her bewildered, troubled gaze—many of them. Deduction was easy out there in the lonely night. It was easy to see that Shaw and his companion sat up so late that the servants had gone to bed. Distractedly she looked about for means of shelter on the porch until daylight could abet her in the flight to the village beyond. The storm was sure to come at no far distant time. She knew and feared the violence of the mountain rains. “By all that's holy,” came in a man's voice, low-toned and uncertain; “it is a dream, after all!” She turned like a flash, with a startled exclamation and an instinctive movement as if to shield herself from unbidden gaze. Her lips parted and her heart pounded like a hammer. Standing in the doorway was Randolph Shaw, his figure looming up like monstrous, wavering genie in the uncertain light from the shaking lantern. His right hand was to his brow and his eyes were wide with incredulous joy. She noticed that the left sleeve of his dinner jacket hung limp, and that the arm was in a white sling beneath. “Is it really you?” he cried, his hand going instinctively to his watch-pocket as if doubting that it was night instead of morning. “I've—I 've run away from them,” she stammered. “It's two o'clock —don't look! Oh, I'm so sorry now—why did I—” “You ran away?” he exclaimed, coming toward her. “Oh, it can't be a dream. You are there, aren't you?” She was a pitiable object as she stood there, powerless to retreat, shaking like a leaf. He took her by the shoulder. “Yes—it is. Good Lord, what does it mean? What has happened? How did you come here? Are you alone?”
  • 70. “Utterly, miserably alone. Oh, Mr. Shaw!” she cried despairingly. “You will understand, won't you?” “Never! Never as long as I live. It is beyond comprehension. The wonderful part of it all is that I was sitting in there dreaming of you —yes, I was. I heard some one out here, investigated and found you —you, of all people in the world. And I was dreaming that I held you in my arms. Yes, I was! I was dreaming it—” “Mr. Shaw! You should n't—” “And I awoke to find you—not in my arms, not in Bazelhurst Villa, but here—here on my porch.” “Like a thief in the night,” she murmured. “What do you think of me?” “Shall I tell you—really?” he cried. The light in his eyes drove her back a step or two, panic in her heart. “N—no, no—not now!” she gasped, but a great wave of exaltation swept through her being. He turned and walked away, too dazed to speak. Without knowing it, she followed with hesitating steps. At the edge of the porch he paused and looked into the darkness. “By Jove, I must be dreaming,” she heard him mutter. “No, you are not,” she declared desperately. “I am here. I ask your protection for the night. I am going away—to England—to-morrow. I could n't stay there—I just could n't. I'm sorry I came here—I'm—” “Thank heaven, you did come,” he exclaimed, turning to her joyously. “You are like a fairy—the fairy princess come true. It's unbelievable! But—but what was it you said about England?” he concluded, suddenly sober. “I am go—going home. There's no place else. I can't live with her,” she said, a bit tremulously. “To England? At once? Your father—will he—?” “My father? I have no father. Oh!” with a sudden start Her eyes met his in a helpless stare. “I never thought. My home was at
  • 71. Bazelhurst Castle—their home. I can't go there. Good heavens, what am I to do?” A long time afterward she recalled his exultant exclamation, checked at its outset,—recalled it with a perfect sense of understanding. With rare good taste he subdued whatever it was that might have struggled for expression and simply extended his right hand to relieve her of the lantern. “We never have been enemies, Miss Drake,” he said, controlling his voice admirably. “But had we been so up to this very instant, I am sure I 'd surrender now. I don't know what has happened at the Villa. It does n't matter. You are here to ask my protection and my help. I am at your service, my home is yours, my right hand also. You are tired and wet and—nervous. Won't you come inside? I 'll get a light in a jiffy and Mrs. Ulrich, my housekeeper, shall be with you as soon as I can rout her out. Come in, please.” She held back doubtfully, a troubled, uncertain look in her eyes. “You will understand, won't you?” she asked simply. “And no questions asked,” he said from the doorway. Still she held back, her gaze going involuntarily to the glasses on the table. He interpreted the look of inquiry. “There were two of us. The doctor was here picking out the shot, that 's all. He 's gone. It's all right. Wait here and I'll get a light.” The flame in her lantern suddenly ended its feeble life. She stood inside his doorway and heard him shuffle across the floor in search of the lamps. “Dark as Egypt, eh?” he called out from the opposite side of the room. “Not as dark as the forest, Mr. Shaw.” “Good heavens, what a time you must have had. All alone, were you?” “Of course. I was not eloping.”
  • 72. “I beg your pardon.” “Where were you sitting when I came up?” “Here—in the dark. I was waiting for the storm to come and dozed away, I daresay. I love a storm, don't you?” “Yes, if I 'm indoors. Ah!” He had struck a match and was lighting the wick of a lamp beside the huge fireplace. “I suppose you think I 'm perfectly crazy. I 'm horrid.” “Not at all. Sit down here on the couch, please. More cheerful, eh? Good Lord, listen to the wind. You got here just in time. Now, if you'll excuse me, I'll have Mrs. Ulrich down in a minute. She'll take good care of you. And I 'll make you a nice hot drink, too. You need it.” In the door of the big living-room he turned to her, a look of extreme doubt in his eyes. “By Jove, I bet I do wake up. It can't be true.” She laughed plaintively and shook her head in humble self- abasement. “Don't be lonesome. I'll be back in a minute.” “Don't hurry,” she murmured apologetically. Then she settled back limply in the wide couch and inspected the room, his footsteps noisily clattering down the long hallway to the left. She saw, with some misgiving, that it was purely a man's habitation. Shaw doubtless had built and furnished the big cottage without woman as a consideration. The room was large, comfortable, solid; there was not a suggestion of femininity in, it—high or low—except the general air of cleanliness. The furniture was rough-hewn and built for use, not ornamentation; the walls were hung with English prints, antlers, mementoes of the hunt and the field of sport; the floor was covered with skins and great “carpet rag” rugs. The whole aspect was so distinctly mannish that her heart fluttered ridiculously in its loneliness. Her cogitations were running seriously toward riot when he came hurriedly down the hall and into her presence. “She'll be down presently. In fact, so will the cook and the housemaid. Gad, Miss Drake, they were so afraid of the storm that all of them piled into Mrs. Ulrich's room. I wonder at your courage in facing the symptoms outdoors. Now, I'll fix you a drink. Take off
  • 73. your hat—be comfortable. Cigarette? Good! Here's my sideboard. See? It's a nuisance, this having only one arm in commission; affects my style as a barkeep. Don't stir; I'll be able—” “Let me help you. I mean, please don't go to so much trouble. Really I want nothing but a place to sleep to-night. This couch will do—honestly. And some one to call me at daybreak, so that I may be on my way.” He looked at her and laughed quizzically. “Oh, I'm in earnest, Mr. Shaw, I would not have stopped here if it had n't been tor the storm.” “Come, now, Miss Drake, you spoil the fairy tale. You did intend to come here. It was the only place for you to go—and I'm glad of it. My only regret is that the house is n't filled with chaperons.” “Why?” she demanded with a guilty start. “Because I could then say to you all the things that are in my heart—aye, that are almost bursting from my lips. I—I can't say them now, you know,” he said, and she understood his delicacy. For some minutes she sat in silence watching him as he clumsily mixed the drinks and put the water over the alcohol blaze. Suddenly he turned to her with something like alarm in his voice. “By George, you don't suppose they 'll pursue you?” “Oh, would n't that be jolly? It would be like the real story-book— the fairy and the ogres and all that. But,” dubiously, “I'm sorely afraid they consider me rubbish. Still—” looking up encouragingly —“my brother would try to find me if he—if he knew that I was gone.” To her surprise, he whistled softly and permitted a frown of anxiety to creep over his face. “I had n't thought of that,” he observed reflectively. Then he seemed to throw off the momentary symptoms of uneasiness, adding, with a laugh: “I daresay nothing will happen. The storm would put a stop to all idea of pursuit.” “Let them pursue,” she said, a stubborn light in her eyes. “I am my own mistress, Mr. Shaw. They can't take me, willy nilly, as if I were a child, you know.”
  • 74. “That's quite true. You don't understand,” he said slowly, his back to her. “You mean the law? Is it different from ours?” “Not that. The—er—situation. You see, they might think it a trifle odd if they found you here—with me. Don't you understand?” He turned to her with a very serious expression. She started and sat bolt upright to stare at him comprehensively. “You mean—it—it isn't quite—er—” “Regular, perhaps,” he supplied. “Please keep your seat! I'm not the censor; I'm not even an opinion. Believe me, Miss Drake, my
  • 75. only thought was and is for your good.” “I see. They would believe evil of me if they knew I had come to you,” she mused, turning quite cold. “I know the kind of people your sister-in-law has at her place, Miss Drake. Their sort can see but one motive in anything. You know them, too, I daresay.” “Yes, I know them,” she said uneasily. “Good heavens, what a fool I've been,” she added, starting to her feet. “I might have known they 'll say all sorts of terrible things. They must not find me here. Mr. Shaw, I'm—I am so ashamed—I wonder what you are thinking of me.” Her lip trembled and there was such a pleading look in her dark eyes that he controlled himself with difficulty. It was only by imposing the severest restraint upon his susceptibilities that he was able to approach her calmly. “I can't tell you now—not here—what I am thinking. It is n't the place. Maybe—maybe you can read my thought. Please—Miss Drake. Look up, please. Can't you read—oh, there now—I beg your pardon! You come to me for protection and I—well, don't be too hard on me just yet. I'll find the time and place to tell you.” He drew away almost as his hand was ready to clasp hers—all because her sweet eyes met his trustingly—lovingly. “Just now I am a poor little reprobate,” she sighed ever so miserably. “You are very good. I'll not forget.” “I 'll not permit you to forget,” he said eagerly. “Is n't the housekeeper a long time in coming?” she asked quickly. He laughed contentedly. “We've no reason to worry about her. It 's the pursuers from Bazelhurst that should trouble us. Won't you tell me the whole story?” And she told him everything, sitting there beside him with a hot drink in her hand and a growing shame in her heart. It was dawning upon her with alarming force that she was exposing a hitherto unknown incentive. It was not a comfortable awakening.
  • 76. “And you champion me to that extent?” he cried joyously. She nodded bravely and went on. “So here I am,” she said in conclusion. “I really could not have walked to Ridgely to-night, could I?” “I should say not.” “And there was really nowhere else to come but here?” dubiously. “See that light over there—up the mountain?” he asked, leading her to a window. “Old man Grimes and his wife live up there. They keep a light burning all night to scare Renwood's ghost away. By Jove, the storm will be upon us in a minute. I thought it had blown around us.” The roll of thunder came up the valley. “Thank heaven, you 're safe indoors. Let them pursue if they like. I 'll hide you if they come, and the servants are close-mouthed.” “I don't like the way you put it, Mr. Shaw.” “Hullo, hullo—the house,” came a shout from the wind-ridden night outside. Two hearts inside stopped beating for a second or two. She caught her breath sharply as she clasped his arm. “They are after me!” she gasped. “They must not find you here. Really, Miss Drake, I mean it. They would n't understand. Come with me. Go down this hall quickly. It leads to the garden back of the house. There's a gun-room at the end of the hall. Go in there, to your right. Here, take this! It's an electric saddle-lantern. I 'll head these fellows off. They shan't find you. Don't be alarmed.” She sped down the narrow hall and he, taking time to slip into a long dressing-coat, stepped out upon the porch in response to the now prolonged and impatient shouts. “Who 's there?” he shouted. The light from the windows revealed several horsemen in the roadway. “Friends,” came back through the wind. “Let us in out of the storm. It's a terror.”
  • 77. “I don't know you.” There was a shout of laughter and some profanity. “Oh, yes you do, Mr. Shaw. Open up and let us in. It's Dave Rank and Ed Hunter. We can't make the cabin before the rain.” Shaw could see their faces now and then by the flashes of lightning and he recognized the two woodsmen, who doubtless had been visiting sweethearts up toward Ridgely. “Take your horses to the stable, boys, and come in,” he called, laughing heartily. Then he hurried off to the gun-room. He passed Mrs. Ulrich coming downstairs yawning prodigiously; he called to her to wait for him in the library. There was no one in the gun-room; the door leading to the back porch was open. With an exclamation he leaped outside and looked about him. “Good heavens!” he cried, staggering back. Far off in the night, a hundred yards or more up the road, leading to Grimes' cabin he saw the wobbling, uncertain flicker of a light wending its way like a will-o'-the-wisp through the night. Without a moment's hesitation and with something strangely like an oath, he rushed into the house, almost upsetting the housekeeper in his haste. “Visitors outside. Make 'em comfortable. Back soon,” he jerked out as he changed his coat with small respect for his injured arm. Then he clutched a couple of raincoats from the rack and flew out of the back door like a man suddenly gone mad.
  • 79. T CHAPTER VI—IN WHICH A GHOST TRESPASSES he impulse which drove Penelope out for the second time that night may be readily appreciated. Its foundation was fear; its subordinate emotions were shame, self-pity and consciousness of her real feeling toward the man of the house. The true spirit of womanhood revolted with its usual waywardness. She was flying down the stony road, some distance from the cottage, in the very face of the coming tornado, her heart beating like a trip-hammer, her eyes bent on the little light up the mountain- side, before it occurred to her that this last flight was not only senseless but perilous. She even laughed at herself for a fool as she recalled the tell-tale handbag on the porch and the damning presence of a Bazelhurst lantern in the hallway. The storm which had been raging farther down the valley was at last whirling up to the hill-tops, long delayed as if in gleeful anticipation of catching her alone and unprotected. The little electric saddle-lamp that she carried gave out a feeble glow, scarce opening the way in the darkness more than ten feet ahead. Rough and irksome was the road, most stubborn the wall of wind. The second threat of the storm was more terrifying than the first; at any instant it was likely to break forth in all its slashing fury—and she knew not whither she went. Even as she lost heart and was ready to turn wildly back in an effort to reach Shaw's home before the deluge, the lightning flashes revealed to her the presence of a dwelling just off the road not two hundred feet ahead. She stumbled forward, crying like a frightened child. There were no lights. The house looked dark, bleak, unfriendly. Farther up the hillside still gleamed the little light that
  • 80. was meant to keep Renwood's ghost from disturbing the slumbers of old man Grimes and his wife. She could not reach that light, that much she knew. Her feet were like hundredweights, her limbs almost devoid of power; Grimes' hut appeared to be a couple of miles away. With a last, breathless effort, she turned off the road and floundered through weeds and brush until she came to what proved to be the rear of the darkened house. Long, low, rangy it reached off into the shadows, chilling in its loneliness. There was no time left for her to climb the flight of steps and pound on the back door. The rain was swishing in the trees with a hiss that forbade delay. She threw herself, panting and terror-stricken, into the cave-like opening under the porch, her knees giving way after the supreme effort. The great storm broke as she crouched far back against the wall; her hands over her ears, her eyes tightly closed. She was safe from wind and rain, but not from the sounds of that awful conflict. The lantern lay at her feet, sending its ray out into the storm with the senseless fidelity of a beacon light. “Penelope!” came a voice through the storm, and a second later a man plunged into the recess, crashing against the wall beside her. Something told her who it was, even before he dropped beside her and threw his strong arm about her shoulders. The sound of the storm died away as she buried her face on his shoulder and shivered so mightily that he was alarmed. With her face burning, her blood tingling, she lay there and wondered if the throbbing of her heart were not about to kill her. He was crying something into her ear—wild, incoherent words that seemed to have the power to quiet the storm. And she was responding—she knew that eager words were falling from her lips, but she never knew what they were—responding with a fervour that was overwhelming her with joy. Lips met again and again and there was no thought of the night, of the feud, the escapade, the Renwood ghost—or of aught save the two warm living human bodies that had found each other.
  • 81. The storm, swerving with the capricious mountain winds, suddenly swept their refuge with sheets of water. Randolph Shaw threw the raincoats over his companion and both laughed hysterically at their plight, suddenly remembered. “We can't stay here,” he shouted. “We can't go out into it,” she cried. “Where are we?” “Renwood's,” he called back. Their position was untenable. He was drenched; the raincoats protected her as she crouched back into the most remote corner. Looking about, he discovered a small door leading to the cellar. It opened the instant he touched the latch. “Come, quick,” he cried, lifting her to her feet. “In here—stoop! I have the light. This is the cellar. I'll have to break down a door leading to the upper part of the house, but that will not be difficult. Here's an axe or two. Good Lord, I'm soaked!” “Whe—where are we going?” she gasped, as he drew her across the earthern floor. “Upstairs. It's comfortable up there.” They were at the foot of the narrow stairway. She held back. “Never! It's the—the haunted house! I can't—Randolph.” “Pooh! Don't be afraid. I'm with you, dearest.” “I know,” she gulped, “only one arm. Oh, I can't!” “It's all nonsense about ghosts. I've slept here twenty times, Penelope. People have seen my light and my shadow, that 's all. I'm a pretty substantial ghost.” “Oh, dear! What a disappointment. And there are no spooks? Not even Mrs. Renwood?” “Of course she may come back, dear, but you'd hardly expect a respectable lady spook to visit the place with me stopping here. Even ghosts have regard for conventionalities. She could n't—”
  • 82. “How much more respectable than I,” Penelope murmured plaintively. “Forgive me,” he implored. “I would—only you are so wet.” The door above was locked, but Shaw swung the axe so vigorously that any but a very strong-nerved ghost must have been frightened to death once more. “It's my house, you know,” he explained from the top step. “There we are! Come up, Penelope. The fort is yours.” She followed him into the hall above. In silence they walked along the bare floors through empty rooms until at last he opened a door in what proved to be the left wing. To her surprise, this room was comfortably furnished. There were ashes in the big fireplace and there were lamps which had been used recently—for they were filled with oil. “Here's where I read sometimes,” he explained. “I have slept on that couch. Last winter I came up here to hunt. My cottage wasn't finished, so I stayed here. “I'll confess I've heard strange sounds—now, don't shiver! Once or twice I've been a bit nervous, but I'm still alive, you see.” He lighted the wicks in the two big lamps while she looked on with the chills creeping up and down her back. “I'll have a bully fire in the fireplace in just a minute.” “Let me help you,” she suggested, coming quite close to him with uneasy glances over her shoulders. Ten minutes later they were sitting before a roaring fire, quite content even though there was a suggestion of amazed ghosts lurking in the hallway behind them. No doubt old man Grimes and his wife, if they awoke in the course of the night, groaned deep prayers in response to the bright light from the windows of the haunted house. Shaw and Penelope smiled securely as they listened to the howling storm outside.
  • 83. “Well, this is trespassing,” she said, beaming a happy smile upon him. “I shall be obliged to drive you out, alas,” he said reflectively. “Do you recall my vow? As long as you are a Bazelhurst, I must perforce eject you.” “Not to-night!” she cried in mock dismay. “But, as an alternative, you'll not be a Bazelhurst long,” he went on eagerly, suddenly taking her hands into his, forgetful of the wounded left. “I'm going to try trespassing myself. To-morrow I 'm going to see your brother. It 's regular, you know. I'm going to tell the head of your clan that you are coming over to Shaw, heart and hand.” “Oh!” she exclaimed. “You—you—no, no! You must not do that!” “But, my dear, you are going to marry me.” “Yes—I—suppose so,” she murmured helplessly. “That is n't what I meant. I mean, it is n't necessary to ask Cecil. Ask me; I'll consent for him.” Half an hour passed. Then he went to the window and looked out into the storm. “You must lie down and get some sleep,” he insisted, coming back to her. “The storm's letting up, but we can't leave here for quite a while. I'll sit up and watch. I'm too happy to sleep.” She protested, but her heavy eyes were his allies. Soon he sat alone before the fire; she slept sound on the broad couch in the corner, a steamer rug across her knees. A contented smile curved his lips as he gazed reflectively into the flames. He was not thinking of Mrs. Renwood's amiable ghost. How long she had been asleep, Penelope did not know. She awoke with a start, her flesh creeping. A nameless dread came over her; she felt that she was utterly alone and surrounded by horrors. It was a full minute—a sickening hour, it seemed—before she realized that she was in the room with the man she loved. Her frightened eyes
  • 84. caught sight of him lying back in the chair before the dying fire in the chimney place. The lights were low, the shadows gaunt and chill. A terrified exclamation started to her lips. Her ears again caught the sound of some one moving in the house—some alien visitor. There was no mistaking the sound—the distant, sepulchral laugh and the shuffling of feet, almost at the edge of the couch it seemed. “Randolph!” she whispered hoarsely. The man in the chair did not move. She threw off the blanket and came to a sitting posture on the side of the couch, her fingers clutching the covering with tense horror. Again the soft, rumbling laugh and the sound of footsteps on the stairway. Like a flash she sped across the room and clutched frantically at Randolph's shoulders. He awoke with an exclamation, staring bewildered into the horrified face above. “The—the ghost!” she gasped, her eyes glued upon the hall door. He leaped to his feet and threw his arms about her. “You've had a bad dream,” he said. “What a beast I was to fall asleep. Lord, you're frightened half out of your wits. Don't tremble so, dearest. There's no ghost. Every one knows—” “Listen—listen!” she whispered. Together they stood motionless, almost breathless before the fire, the glow from which threw their shadows across the room to meet the mysterious invader. “Good Lord,” he muttered, unwilling to believe his ears. “There is some one in the house. I 've—I've heard sounds here before, but not like these.” Distinctly to their startled ears came the low, subdued murmur of a human voice and then unmistakable moans from the very depth of the earth—from the grave, it seemed. “Do you hear?” she whispered. “Oh, this dreadful place! Take me away, Randolph, dear,—” “Don't be afraid,” he said, drawing her close. “There's nothing supernatural about those sounds. They come from lips as much alive as ours. I 'll investigate.” He grabbed the heavy poker from the chimney corner, and started toward the door. She followed close
  • 85. behind, his assurance restoring in a measure the courage that had temporarily deserted her. In the hallway they paused to look out over the broad porch. The storm had died away, sighing its own requiem in the misty tree-tops. Dawn was not far away. A thick fog was rising to meet the first glance of day. In surprise Shaw looked at his watch, her face at his shoulder. It was after five o'clock. “Ghosts turn in at midnight, dear,” he said with a cheerful smile. “They don't keep such hours as these.” “But who can it be? There are no tramps in the mountains,” she protested, glancing over her shoulder apprehensively. “Listen! By Jove, that voice came from the cellar.” “And the lock is broken,” she exclaimed. “But how silly of me! Ghosts don't stop for locks.” “I 'll drop the bolts just the same,” he said, as they hurried down the hallway. At the back stairs they stopped and listened for many minutes. Not a sound came up to them from below. Softly he closed the door and lowered two heavy bars into place. “If there's any one down there they probably think they've heard spooks trotting around up here.” “Really, it's quite thrilling, isn't it?” she whispered, in her excitement. “In any event, we're obliged to remain under cover until they depart,” he said thoughtfully. “We can't be seen here, dearest.” “No,” she murmured, “not even though it is our house.” They returned to the big room as softly as mice and he left her a moment later to close the heavy window shutters on the porch. When he returned there was a grim smile on his face and his voice shook a little as he spoke. “I've heard the voices again. They came from the laundry, I think. The Renwoods were downright Yankees, Penelope; I will swear that
  • 86. these voices are amazingly English.”
  • 87. T CHAPTER VII—IN WHICH THE AUTHOR TRESPASSES HIS narrative has quite as much to do with the Bazelhurst side of the controversy as it has with Shaw's. It is therefore but fair that the heroic invasion by Lord Cecil should receive equal consideration from the historian. Shaw's conquest of one member of the force opposing him was scarcely the result of bravery; on the other hand Lord Cecil's dash into the enemy's country was the very acme of intrepidity. Shaw had victory fairly thrust upon him; Lord Bazelhurst had a thousand obstacles to overcome before he could even so much as stand face to face with the enemy. Hence the expedition that started off in the wake of the deserter deserves more than passing mention. Down the drive and out into the mountain road clattered the three horsemen. Lady Bazelhurst, watching at the window casement, almost swooned with amazement at the sight of them. The capes of their mackintoshes seemed to flaunt a satirical farewell in her face; their owners, following the light of the carriage lamps, swept from view around a bend in the road. His lordship had met the duke in the hall, some distance from that nobleman's room, and, without observing Barminster's apparent confusion, commanded him to join in the pursuit. Barminster explained that he was going to see how the cook was resting; however, he would go much farther to be of service to the runaway sister of his host. “She's broken-hearted,” half sobbed the brother. “Yes,” agreed the duke; “and what's a broken leg to a broken heart? Penelope's heart, at that. Demme, I can't find the cook's room, anyway.”
  • 88. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com