Implement Features¶
Enable rapid onboarding to project development
Our goal is to create a Tetris Game to delight our site visitors, without losing time to complex project onboarding process nor complications due to tool-bloat.
Currently, navigating to the Tetris Game page of the workshop site shows that the feature is currently missing. We will address that issue in this exercise.
Exercise: Integrate the Tetris Game¶
Refer back to the Codespaces development environment created in the prerequisite to the workshop.(1)
-
Your Codespace may have stopped due to inactivity. Do not worry, it is quite easy to get back on track...
- If the browser tab with your Codespace remains open and you can find it, click to resume.
- Otherwise, you can find it at the new repository you had created.
Explore your Codespace¶
Understand Your Codespace¶
.devcontainer/devcontainer.json
describes the provisioning of your codespace. Some of the configuration entries are explained below, with annotations next to the respective entry. You can learn more about the Development Container Specification at your convenience.
- You can customize the compute resource to be made available for the Codespace environment, to suit your project.
- A
Dockerfile
can be used to customize the Codespace container image, for instance you may choose to consistently pre-install dependencies required for the development environment. - Tasks may be configured to be executed at the start of each development session e.g. running a development server.
On the TERMINAL
view at the bottom, notice that a local site server is already running. This is as a result of the postAttachCommand
configuration entry in .devcontainer/devcontainer.json
.
Looking at the build log in the terminal, you can see a warning like the one in the following example.(1)
- ๐ก The warning gives a cue to addressing the Tetris Game integration issue. We shall implement the fix in later steps!
The log INFO
entry that reads INFO - [05:36:30] Watching paths for changes: 'docs', 'mkdocs.yml'
informs you that thelocal site will rebuild whenever there is a change in the docs
folder.
Enable Quick Collaboration Feedback¶
Switch to the PORTS
view on the bottom panel, notice there is a Site (8080)
entry in the table.
- Focus your mouse pointer on the
Site (8080)
to reveal additional contexts. -
Click the Preview in Editor icon to browse the local build of the site inside of the editor's browser.(1)
-
- Only you currently have access to the published site.
- You may instead click the icon associated with
Site (8080)
entry to view the site in your normal browser.
-
Open access to other stakeholders for collaboration.
- Right click on the
Site (8080)
entry - In the popup menu, set the mouse pointer on the Port Visibility item and select the Public option.
Now, other stakeholders you share the site URL with can access the site. Consequently, they can also assess your ongoing work and can collaborate with timely feedbacks.
Implement Automated Checks¶
GitHub as a platform, is event-driven. Beyond the ordinary, you can generally automate your actual business processes by modelling activities to produce changes on GitHub, thus triggering execution of certain automated tasks depending on the nature of a change. If you already familiar with the concept of GitOps, think of how the idea can be extended beyond the scopes of provisioning infrastructure and implementing continuos deployment.
At this fundamentals phase of introduction to DevSecOps, we shall focus our leverage of GitHub's powerful event system to drive continuous integration checks and tests with GitHub Workflows.
Learn GitHub Actions¶
What is GitHub Actions?
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository, or deploy merged pull requests to production.
GitHub Actions goes beyond just DevOps and lets you run workflows when other events happen in your repository. For example, you can run a workflow to automatically add the appropriate labels whenever someone creates a new issue in your repository.
GitHub provides Linux, Windows, and macOS virtual machines to run your workflows, or you can host your own self-hosted runners in your own data center or cloud infrastructure.
name: Learn GitHub Actions #(1)!
run-name: ${{ github.actor }} is learning GitHub Actions #(2)!
on: [push] #(3)!
permissions: #(12)!
contents: read
env: #(13)!
LEARNER_NAME: Igwe
jobs: #(4)!
check-bats-version: #(5)!
runs-on: ubuntu-latest #(6)!
steps: #(7)!
- uses: actions/checkout@v4 #(8)!
- uses: actions/setup-node@v3 #(9)!
with:
node-version: '14'
- run: npm install -g bats #(10)!
- run: bats -v #(11)!
- run: echo "Hey ${LEARNER_NAME}, you're good... You've mastered GitHub Actions\!"
Optional
- The name of the workflow as it will appear in the "Actions" tab of the GitHub repository. If this field is omitted, the name of the workflow file will be used instead.Optional
- The name for workflow runs generated from the workflow, which will appear in the list of workflow runs on your repository's "Actions" tab. This example uses an expression with thegithub
context to display the username of the actor that triggered the workflow run. For more information, see "Workflow syntax for GitHub Actions."- Specifies the trigger for this workflow. This example uses the
push
event, so a workflow run is triggered every time someone pushes a change to the repository or merges a pull request. This is triggered by a push to every branch; for examples of syntax that runs only on pushes to specific branches, paths, or tags, see "Workflow syntax for GitHub Actions" and "Events that trigger workflows" . - Groups together all the jobs that run in the
learn-github-actions
workflow. - Defines a job named
check-bats-version
. The child keys will define properties of the job. - Configures the job to run on the latest version of an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by GitHub. For syntax examples using other runners, see "Workflow syntax for GitHub Actions"
- Groups together all the steps that run in the
check-bats-version
job. Each item nested under this section is a separate action or shell script. -
The
uses
keyword specifies that this step will runv4
of theactions/checkout
action. This is an action that checks out your repository onto the runner, allowing you to run scripts or other actions against your code (such as build and test tools). You should use the checkout action any time your workflow will use the repository's code.Actions are the building blocks that power your workflow. A workflow can contain actions created by the community, or you can create your own actions directly within your application's repository.
To learn more, see:
-
This step uses the
actions/setup-node@v3
action to install the specified version of the Node.js. (This example uses version 14.) This puts both thenode
andnpm
commands in yourPATH
. - The
run
keyword tells the job to execute a command on the runner. In this case, you are usingnpm
to install thebats
software testing package. - Finally, you'll run the
bats
command with a parameter that outputs the software version. -
At the start of each workflow job, GitHub automatically creates a unique
GITHUB_TOKEN
secret to use in your workflow. You can use theGITHUB_TOKEN
to authenticate in the workflow job.When you enable GitHub Actions, GitHub installs a GitHub App on your repository. The
GITHUB_TOKEN
secret is a GitHub App installation access token. You can use the installation access token to authenticate on behalf of the GitHub App installed on your repository. The token's permissions are limited to the repository that contains your workflow.You can modify the permissions for the
GITHUB_TOKEN
in individual workflow files. If the default permissions for theGITHUB_TOKEN
are restrictive, you may have to elevate the permissions to allow some actions and commands to run successfully. If the default permissions are permissive, you can edit the workflow file to remove some permissions from theGITHUB_TOKEN
. As a good security practice, you should grant theGITHUB_TOKEN
the least required access.Learn more about the default Permissions for the
GITHUB_TOKEN
. -
This defines a
map
of variables that are available to the steps of all jobs in the workflow. You can also set variables that are only available to the steps of a single job or to a single step. Learn more at Defining environment variables for a single workflow.
Implement Automated Pull Request Checks¶
What is a Pull Request (also known as PR)?
Pull requests let you tell others about changes you've pushed to a branch in a repository on GitHub. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged into the base branch.
To enable quality checks in the project at high velocity, implement a workflow that standardizes automated checks as follows.
Analysis¶
-
Lines
3 - 6
The workflow will be triggered when a pull request is created targeting the
main
branch. Additional, changes to a pull request will cause the workflow to rerun. -
Lines
43 - 45
First check: The site is built with the
--strict
option, such that the occurrence of anyWARNING
results in a failed check. As it is, we can expect the automated checks to flag the pull request as non-compliant at this step. -
Lines
47 - 48
Second check: Provided the build step had been successful, this next step tests the correctness of the feature implementation in accordance to customer-value expectations. So far, we should not get to this point in the workflow run as the
Build
should have failed because the Tetris game feature implementation has not been completed.
DEPRECATED EXERCISE STEP
Optionally Implement Merge Queue for GitHub Enterprise
What is a Merge Queue?
A merge queue helps increase velocity by automating pull request merges into a busy branch and ensuring the branch is never broken by incompatible changes.
The merge queue provides the same benefits as the Require branches to be up to date before merging branch protection, but does not require a pull request author to update their pull request branch and wait for status checks to finish before trying to merge.
Using a merge queue is particularly useful on branches that have a relatively high number of pull requests merging each day from many different users.
Once a pull request has passed all required branch protection checks, a user with write access to the repository can add the pull request to the queue. The merge queue will ensure the pull request's changes pass all required status checks when applied to the latest version of the target branch and any pull requests already in the queue.
๐ Learn more...
The previously implemented pull request checks will be executed in isolation. However, to provide assurance of stability on the target branch as different changes are being introduced to it at a fast pace by multiple collaborators, we want to aggregate isolated changes and re-validate them in batches i.e. the Merge Queue.
Is this like a Daily Build?
You probably recognize this concept as similar to the implementation of a daily/nightly build. Except you do not have to wait ~ 24 hours or there about to validate your project's quality status.
Configure Merge Queue
A Merge Queue is ideal for rolling out continuous integration at scale, enabling larger projects and teams to be optimally productive -- delivering high quality value without compromising product stability.
You can reserve execution of expensive checks in a merge queue, to save cost and time.
To effectively leverage Merge Queue, you must first configure your repository to require it for pull requests as follows.
- On GitHub.com, navigate to the main page of the repository you have created.
- Under your repository name, click Settings. If you cannot see the "Settings" tab, select the dropdown menu, then click Settings.
- In the "Code and automation" section of the sidebar, click Branches.
- Next to "Branch protection rules", click Add branch protection rule.
- Under "Branch name pattern", type the branch name
main
for the branch you want to protect. - Select Require merge queue.
- Click to complete Merge Queue configuration
Finally implement the checks in merge queue as follows.
name: Run Checks on Merge Queue
on:
merge_group:
types: [checks_requested]
permissions:
actions: write
checks: write
contents: read
security-events: write
pull-requests: write
env:
CI: true
SITE_DIR: site
TETRIS_APP_HOST: "127.0.0.1"
TETRIS_APP_PORT: "8080"
TETRIS_APP_PATH: "github-devsecops-fundamentals"
jobs:
run-acceptance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.12
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.ci.txt
npm ci
# Install browsers for running functional tests
npx playwright install --with-deps chromium
- name: Build
run: |
python -m mkdocs build --clean --strict --verbose --site-dir '${{ env.SITE_DIR }}'
- name: Functional Test
run: npx playwright test
- name: Upload Functional Test Report
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
Publish your changes¶
You can link your changes to an issue
Recall the issue you created earlier and its respective issue number, you will use it to link your current changes to the issue.
-
Commit and push the changes.
-
Create a pull request by clicking on the GitHub icon in the sidebar menu, and then clicking the Create Pull Request icon.
Check that the local branch and repository you're merging from, and the remote branch and repository you're merging into, are correct. You may leave the pre-filled pull request title and description as they are.
Click "Create", and if prompted then click "Always" or "Publish Branch".
-
The pull request you created will be listed at
https://github.com/<YOUR-HANDLE>/github-devsecops-fundamentals/pulls
.Opening the pull request for exploration you should observe the following
-
Conversation
Particularly enables and summarizes discussions/reviews on your changes with other collaborators and stakeholders. And additionally summarizes outcome of checks on the pull request. - Commits
Summarizes all the commits contributing to the pull request.
-
Checks
Lists the checks run on the pull request and their respective outcomes.
-
Files changed
Shows a
diff
of files modified and added due to the pull request.
Note
Observe the 3 executed checks.
- 1 failure due to error in site build.
- 2 code scanning check passes.
-
Implement Feature Changes¶
The Build
step in the previously implemented automated checks should identify a failure ultimately pointing to incompletion of the expected Tetris game feature. In the current phase, we will take steps to integrate the Tetris game as follows.
- Rename the
docs/.tetris.game
folder todocs/tetris.game
, i.e. simply remove the.
prefix from the name. -
Find and open the file
mkdocs.yml
in the File Explorer (it's at the root of the file tree) -
Confirm that the
Tetris Game
relevant entry points to an index file in thetetris.game
folder
Manual Test¶
- Observe the local build in the terminal, there should not be any
WARNING
in the log. - Manually confirm that the Tetris Game integration was effective.
Automated Test¶
Before publishing our new changes, we will implement and execute a functional test to validate the feature implementation.
-
Open the terminal and install test dependencies.(1)
- ๐ก You can create additional terminal session by clicking at the top right side of the
TERMINAL
panel.
# Install Node.js nvm install --lts #(1)! # Install packages required for running the functional UI test npm install # Install the browser(s) against which the functional UI test should run npx playwright install --with-deps chromium #(2)!
- A codespace environment can be customized as needed. In this case, we customized the running session by installing the latest version of
Node.js
. - This command installs browsers required for the functional test. Please be patient, it may take 1 to 2 minutes to complete the installation.
Then implement the functional test as follows.
Finally execute the automated test.
When everything has been done right, the test should pass.
- ๐ก You can create additional terminal session by clicking at the top right side of the
-
Commit the changes to the current
feature/tetris-game
branch and publish it for a review.You can link your changes to an issue
Recall the issue you created earlier and its respective issue number, you will use it to link your current changes to the issue.
Observe that all checks have passed.
๐ Resources¶
- Creating a GitHub Pages site
- Introduction to dev containers
- Workflow syntax for GitHub Actions
- Events that trigger workflows
- Finding and customizing actions
- Code scanning
- Security hardening for GitHub Actions