| ← Reusable Workflows | Next: GitHub Actions section overview → |
|---|
Building a CI/CD pipeline is only half the battle — you also need to enforce it. Repository rulesets ensure that code can't be merged without passing checks and getting reviewed. Required workflows go further, allowing organizations to mandate specific workflows across all repositories. In this final exercise, you'll configure a ruleset on main, explore required workflows, and wrap up the workshop.
The shelter's CI/CD pipeline is comprehensive, but nothing currently prevents someone from merging code without passing CI — meaning untested code could reach main and trigger a deployment. The organization also wants to ensure all repositories run security scanning. Let's lock things down with rulesets and explore how required workflows enforce standards at scale.
Rulesets are GitHub's recommended approach for enforcing rules on branches and tags. They offer flexibility and visibility that legacy branch protection rules don't:
- Layering — Multiple rulesets can apply to the same branch; the most restrictive rule wins.
- Status management — Toggle between Active and Disabled without losing configuration.
- Visibility — Anyone with read access can see active rulesets (not just admins).
- Bypass permissions — Granular bypass for specific roles, teams, or GitHub Apps.
- Scope — Repository-level or organization-wide (on GitHub Enterprise).
- Required workflows — Rulesets can require specific workflows to pass before merging.
Rulesets are available on all GitHub plans for public repositories, and on GitHub Pro, Team, and Enterprise plans for private repositories.
One of the most powerful ruleset features is the ability to require specific workflows to pass before merging. This is particularly useful at the organization level:
- An organization creates a reusable workflow (e.g.
security-scan.yml) in a central repository. - An organization-wide ruleset requires that workflow for all (or a subset of) repositories.
- Every PR across those repositories now runs the required workflow automatically — individual repository owners can't skip it.
Common use cases include security scanning, license compliance, and code quality checks.
Right now we have two sets of tests - end to end tests with Playwright, and unit tests with Python. The latter is actually setup using a matrix, where we run the tests against different versions of Python. As time goes on, the list of tests may grow and change. We want to ensure we can easily indicate that all tests have passed in one, centralized report. This will allow us to then use this as our flag when creating a gate, to ensure our CI has completed successfully before allowing a merge into main. We'll do this by adding a new job to the end of our tests workflow, which will check if all jobs in the workflow have succeeded.
-
Open
.github/workflows/run-tests.ymland add the following job at the end of thejobs:section (after thetest-e2ejob):tests-passed: if: always() needs: [test-api, test-e2e] runs-on: ubuntu-latest steps: - name: Check results run: | if [[ "${{ needs.test-api.result }}" != "success" || "${{ needs.test-e2e.result }}" != "success" ]]; then echo "One or more jobs failed" exit 1 fi
-
Commit and push the change:
git add .github/workflows/run-tests.yml git commit -m "Add tests-passed summary job" git push
The if: always() ensures this job runs even when upstream jobs fail, so it can correctly report failure. The needs key creates a dependency on both test jobs, and the step checks their results.
Let's create a ruleset that requires our tests to pass, and pull requests to be reviewed, before merging to main.
-
Navigate to your repository on GitHub.
-
Select Settings, then in the left sidebar under Code and automation, expand Rules and select Rulesets.
-
Select New ruleset > New branch ruleset.
-
Under Ruleset name, enter
main-gate. -
Set the Enforcement status to Active.
-
Under Target branches, select Add target > Include default branch. This targets
main. -
Under Branch rules, enable the following rules:
Rule Configuration Require a pull request before merging Set Required approvals to 1Require status checks to pass Check Require branches to be up to date before merging, then add tests-passedas a required checkBlock force pushes (enabled by default) -
Select Create to save the ruleset.
Tip
If your status checks don't appear when searching, make sure the CI workflow has run at least once on the repository. GitHub only shows status checks that have been reported previously.
Note
You can start a ruleset in Disabled mode to test it before enforcing. This lets you preview which PRs would be blocked without actually blocking anyone.
Let's verify the ruleset is working.
-
Return to your codespace and open the terminal (Ctl+` to toggle). Create a new branch and make a small change:
git checkout -b test-ruleset echo "# test change" >> server/app.py git add server/app.py git commit -m "Test ruleset enforcement" git push -u origin test-ruleset
-
Navigate to your repository on GitHub and create a pull request from
test-rulesettomain. -
Observe that the Merge pull request button is disabled — the required status checks must pass and the PR needs an approving review.
-
Watch the CI workflow run. Even after all checks pass, the merge button remains disabled until the review requirement is satisfied.
-
You can close the pull request — the important thing is that the ruleset is enforced!
Important
Rulesets ensure your CI pipeline isn't just a suggestion — it's a requirement. Code cannot reach main without passing the checks and reviews you've defined. Since your deploy workflow only triggers on pushes to main, this means only validated, reviewed code gets deployed.
Organization-wide rulesets can mandate that specific workflows run across all repositories. This pairs naturally with the reusable workflows you built in the previous exercise — an organization could create a reusable security-scanning workflow in a central .github repository, then enforce it via a ruleset so every PR across the organization runs it automatically.
Note
Organization-wide rulesets are available on GitHub Team and GitHub Enterprise plans. For personal repositories on the Free plan, repository-level rulesets (as configured above) provide similar enforcement at the repo level.
Here are some additional GitHub Actions features you can explore on your own:
- Service containers: Spin up databases, caches, or other services alongside your test jobs. Define them under
servicesin a job, and GitHub Actions handles the lifecycle for you. - Job summaries: Write Markdown to the
$GITHUB_STEP_SUMMARYenvironment file to create rich, formatted output that appears on the workflow run summary page. - Self-hosted runners: Run workflows on your own infrastructure for specialized hardware needs, compliance requirements, or to stay within your network. Useful when you need GPUs, specific OS versions, or access to internal resources.
- Larger runners: GitHub-hosted runners with more CPU and memory (up to 96-core x64 and 64-core ARM), available on Team and Enterprise plans. Swap
runs-on: ubuntu-latestfor a larger runner label when your builds or tests need more compute. See the larger runners documentation. repository_dispatch: Trigger workflows from external events via the GitHub API. This is useful for integrating GitHub Actions with external systems like monitoring tools, chatbots, or other CI/CD platforms.
Congratulations! You've built a complete CI/CD pipeline for the pet shelter application. Let's review what you've accomplished:
- Continuous integration: Tests run on every push and pull request across multiple Python versions, catching bugs before they reach
main. - Continuous deployment: Automated deployment to Azure via
azd, triggered after CI passes onmain. - Custom actions: Encapsulated Python setup and database seeding into a reusable composite action, eliminating duplication across jobs.
- Reusable workflows: Extracted the deployment pattern into a callable workflow template, shared by both the automated CD pipeline and a manual deploy workflow for rollbacks.
- Manual deployment: Added on-demand deployment capability for rollbacks and hotfixes, using
workflow_dispatchwith a git ref input. - Rulesets: Enforced quality gates so code can't be merged without passing CI checks and peer review — the production safeguard that ensures only validated code gets deployed.
This pipeline follows the same patterns used by teams across GitHub. As the shelter's application grows, this foundation will scale with it.
If you want to keep exploring, here are some suggested next steps:
- Add a code scanning workflow using GitHub Advanced Security.
- Explore GitHub Environments with deployment protection rules for staged deployments (e.g., staging → production with manual approval).
- Explore the GitHub Actions Marketplace for community-built actions.
- Take the GitHub Skills: Deploy to Azure course for a deeper dive into Azure deployment.
- About rulesets
- Creating rulesets for a repository
- Available rules for rulesets
- The
workflow_dispatchevent - GitHub Skills: Deploy to Azure
- GitHub Actions Marketplace
| ← Reusable Workflows | Next: GitHub Actions section overview → |
|---|