Build a CI Pipeline with GitHub Actions

Write a GitHub Actions workflow that tests your code automatically on every push.

Introduction

30 Second Summary

Every developer has pushed code that accidentally broke something. Without an automated safety net, broken code can sneak into your main branch and cause problems for your entire team.

In this project, you will build a CI/CD pipeline using GitHub Actions that automatically runs your tests every time you push code. By the end, you will have a production-grade workflow that catches bugs before they reach your main branch.

What You'll Build

Push code to your repository, then switch to the GitHub Actions tab and watch your test suite execute in real-time across multiple Node.js versions, all without lifting a finger.

By the end of this project, you'll have:

  • A workflow that automatically runs your tests every time you push or open a pull request, so broken code never reaches your main branch undetected.
  • A matrix build that tests across multiple Node.js versions simultaneously, with cached dependencies so each run completes in seconds instead of minutes.
  • A security-hardened pipeline using least-privilege permissions and concurrency controls that prevent wasted compute on stale runs.
  • Secret Mission: Add a manual trigger with custom inputs and artifact uploads so you can re-run specific tests on demand and download the results.

Are there any prerequisites?

You should be comfortable pushing code to GitHub and creating branches. You also need Git and Node.js installed on your machine. Step 1 walks you through confirming everything is ready.

Before We Start

Before We Start...

Before we dive in, let's lock in what you're about to build and why it matters.

Set Up Your Project

GitHub Actions can only automate what already exists. Before you write your first workflow, you need a repository with real, testable code that the pipeline can run against.

In this step, you'll create a public GitHub repository, install a helpful VS Code extension, and scaffold a Node.js project with passing tests. Once everything works locally, you'll push it up so GitHub Actions has something to build on.

In this step, get ready to:
  • Create a public GitHub repository and clone it locally.
  • Install the GitHub Actions VS Code extension for workflow editing.
  • Scaffold a Node.js project with tests that pass.
Create a GitHub repository and clone it

You need a public repository because GitHub Actions is free and unlimited for public repos. A private repo would eat into your monthly minutes allowance.

  • Open your browser and go to github.com.
  • In the upper-right corner of any page, click the + dropdown menu.
  • Click New repository.
  • Enter github-actions-ci-lab in the Repository name field.
  • Select Public for the repository visibility.
  • Leave all other options unchecked (no README, no .gitignore, no license).
  • Click Create repository.

GitHub shows you a Quick Setup page with the repository URL. You'll use this URL to clone the repository next.

  • Open your terminal. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Clone your new repository by running this command:
git clone https://github.com/[[GITHUB_USERNAME="your-github-username"]]/github-actions-ci-lab.git
  • Move into the cloned repository by running:
cd github-actions-ci-lab
  • Confirm you're inside the repository by running:
ls -la

You should see a .git folder listed. This confirms Git is tracking this directory.

Don't see a .git folder?

Make sure you ran cd github-actions-ci-lab after the clone. If the clone itself failed, double-check that you replaced the username in the URL with your actual GitHub username.

help me troubleshoot why git clone failed

  • Open VS Code with this repository. Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop and select the github-actions-ci-lab folder, then click Open.
Install the GitHub Actions VS Code extension

This extension gives you syntax highlighting, autocomplete, and validation for workflow YAML files. It catches errors before you push, saving you trial-and-error cycles.

  • Open the Extensions panel by pressing Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows).
  • Type GitHub Actions in the search field.
  • Find the extension published by GitHub (the publisher ID is GitHub.vscode-github-actions).
  • Click Install.

You should see the extension appear in your installed extensions list. The extension will activate automatically when you open .yml files in the .github/workflows/ directory later.

Can't find the extension?

Make sure you're searching for GitHub Actions (two words). The correct extension is published by GitHub, not a third party. Look for the verified checkmark next to the publisher name.

help me find and install the GitHub Actions VS Code extension

Scaffold the Node.js project

Now you'll create a small calculator module with tests. The code itself is simple on purpose. The focus of this project is the CI pipeline, not the application logic.

  • Open a terminal inside VS Code by pressing Ctrl+` (backtick key, same shortcut on macOS and Windows).
  • Initialize your Node.js project by running this command:
npm init -y

You'll see the generated package.json printed in the terminal. The defaults need editing, so you'll replace the contents next.

  • Open package.json in the VS Code editor by clicking it in the Explorer sidebar.
  • Select all the content (Cmd+A on macOS or Ctrl+A on Windows) and replace it with the following:
{
  "name": "github-actions-ci-lab",
  "version": "1.0.0",
  "description": "A Node.js project for learning GitHub Actions CI/CD",
  "scripts": {
    "test": "node --test src/"
  },
  "keywords": [],
  "license": "ISC"
}

What does this test script do?

The "test": "node --test src/" script tells Node.js to use its built-in test runner. It automatically finds and runs any files matching *.test.js inside the src/ directory.

This means you don't need to install Jest, Mocha, or any other test framework. Node handles it natively.

  • Save package.json (Cmd+S on macOS or Ctrl+S on Windows).
  • Create the src directory and calculator.js file by running these commands:
mkdir src
touch src/calculator.js
  • Open src/calculator.js in the editor (click it in the Explorer sidebar) and paste the following code:
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

module.exports = { add, subtract, multiply, divide };

What does this module do?

This is a simple arithmetic module with four functions: add, subtract, multiply, and divide. The divide function includes a guard against division by zero.

The module.exports line makes all four functions available to other files that require() this module.

  • Save src/calculator.js.
  • Verify the module loads correctly by running this command in the terminal:
node -e "const c = require('./src/calculator'); console.log(c.add(2, 3));"

You should see 5 printed in the terminal. This confirms your module exports are working.

Seeing 'Cannot find module' error?

Make sure you saved src/calculator.js and that your terminal is in the github-actions-ci-lab folder. Run pwd to check your current directory.

help me fix the 'Cannot find module' error when requiring my calculator

Now you'll write the tests. The test file uses Node's built-in test runner, which provides describe and it blocks just like popular frameworks.

  • Create the test file by running:
touch src/calculator.test.js
  • Open src/calculator.test.js in the editor and paste the following code to set up the imports and test the add and subtract functions:
const { describe, it } = require('node:test');
const assert = require('node:assert');
const { add, subtract, multiply, divide } = require('./calculator');

describe('Calculator', () => {
  describe('add', () => {
    it('adds two positive numbers', () => {
      assert.strictEqual(add(2, 3), 5);
    });

    it('adds negative numbers', () => {
      assert.strictEqual(add(-1, -1), -2);
    });
  });

  describe('subtract', () => {
    it('subtracts two numbers', () => {
      assert.strictEqual(subtract(5, 3), 2);
    });
  });
});

What's happening in this test file?

The node:test module is Node's built-in test runner. You import describe and it to structure your tests into groups and individual checks.

The node:assert module provides assertion functions. strictEqual checks that two values are exactly equal using ===.

  • Save src/calculator.test.js.
  • Run the tests to confirm they pass:
npm test

You should see output showing 3 passing tests (two for add and one for subtract).

Now add the remaining tests for multiply and divide.

  • In src/calculator.test.js, find the closing }); at the very end of the file (the one that closes the top-level describe('Calculator') block).
  • Add the following code just above that closing });:
  describe('multiply', () => {
    it('multiplies two numbers', () => {
      assert.strictEqual(multiply(4, 3), 12);
    });
  });

  describe('divide', () => {
    it('divides two numbers', () => {
      assert.strictEqual(divide(10, 2), 5);
    });

    it('throws on division by zero', () => {
      assert.throws(() => divide(10, 0), {
        message: 'Cannot divide by zero'
      });
    });
  });

What does assert.throws do?

The assert.throws assertion verifies that a function throws an error. You pass it a function that should throw, and an object describing the expected error. Here you're checking that dividing by zero throws an error with the message Cannot divide by zero.

  • Save src/calculator.test.js.

Before you run the tests again, how many tests do you expect to pass now?

  • Run the full test suite by running:
npm test

You should see all 7 tests passing. Two for add, one for subtract, one for multiply, and two for divide. One of those divide tests checks the error case.

✔️ All 7 tests pass

Great work. Your test suite is complete and ready for automation.

ⓧ Some tests are failing

Check that you pasted the multiply and divide test blocks inside the describe('Calculator') block, not after it. The indentation should match the add and subtract blocks above.

help me fix my failing calculator tests

✔️ Awesome, I've got everything!

Great. Double check you've saved both src/calculator.js and src/calculator.test.js.

ⓧ I'd like to double check the full code

Your src/calculator.test.js should contain two sections you built above, in this order:

  • The imports (node:test, node:assert, calculator require) plus the add and subtract test groups.
  • The multiply and divide test groups, placed before the final }); that closes describe('Calculator').

Your package.json should look like this:

{
  "name": "github-actions-ci-lab",
  "version": "1.0.0",
  "description": "A Node.js project for learning GitHub Actions CI/CD",
  "scripts": {
    "test": "node --test src/"
  },
  "keywords": [],
  "license": "ISC"
}

Your src/calculator.js should look like this:

function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

module.exports = { add, subtract, multiply, divide };

Now you need a package-lock.json file. The CI pipeline will use npm ci to install dependencies from the lockfile, which ensures reproducible builds.

  • Generate the lockfile by running:
npm install

You'll see a package-lock.json file appear in your Explorer sidebar.

  • Commit and push all your files to GitHub by running these commands:
git add .
git commit -m "Initial project setup with calculator and tests"
git push

What did git push just do?

Your code now lives on GitHub in the main branch of your github-actions-ci-lab repository. You can verify by refreshing the repository page in your browser. You should see your files listed there.

Push rejected or authentication error?

If Git asks for credentials, you may need to set up a personal access token or SSH key. GitHub no longer accepts passwords for git operations.

help me authenticate with GitHub so I can push my code

Your repository is ready with testable code. Next up, you'll write a GitHub Actions workflow that runs these tests automatically every time you push.

Create Your First Workflow

Your tests pass locally, but there's nothing stopping you from pushing code without running them first. Broken code can reach your main branch undetected.

GitHub Actions solves this by running your tests automatically every time you push. In this step, you'll write a workflow YAML file that tells GitHub exactly what to do when new code arrives.

In this step, get ready to:
  • Create a .github/workflows/ci.yml file that defines your CI pipeline.
  • Push the workflow to GitHub and watch it run your tests automatically.
Create the workflow file

GitHub Actions looks for workflow files in a special directory called .github/workflows/ inside your repository. Any YAML file placed there becomes a workflow that GitHub can run.

  • Create the required directory structure by running this command in your VS Code terminal:
mkdir -p .github/workflows
  • Confirm the directory was created by running:
ls .github

You should see workflows listed in the output.

  • Create a new file called ci.yml inside the .github/workflows/ folder.
  • Add the following workflow configuration to ci.yml:
name: CI

on:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
      - run: npm test

What does this workflow do?

  • name: CI gives the workflow a human-readable label that shows up in the Actions tab.
  • on: push: branches: [main] triggers this workflow every time someone pushes to the main branch.
  • runs-on: ubuntu-latest spins up a fresh Ubuntu virtual machine to run your job.
  • actions/checkout@v7 clones your repository code into the runner so the job can access your files.
  • actions/setup-node@v7 installs Node.js version 22 on the runner.
  • run: npm test executes your test suite, exactly like you ran locally in Step 1.
  • Save ci.yml.

YAML syntax highlighting

The GitHub Actions VS Code extension you installed in Step 1 gives you autocomplete and validation for this file. If you see red squiggly underlines, check your indentation. YAML is sensitive to spaces.

Seeing red underlines in your YAML?

  • YAML uses spaces for indentation, not tabs. Make sure each level is indented by exactly 2 spaces.
  • Check that on: and jobs: are at the root level (no indentation).
  • Make sure the file is saved with the .yml extension, not .yaml (both work for GitHub, but double-check your filename matches ci.yml exactly).

Help me fix my workflow YAML indentation

✔️ Awesome, I've got everything!

Great. Double check you've saved ci.yml and you're ready to push.

ⓧ I'd like to double check the full code

Here is the complete .github/workflows/ci.yml file:

name: CI

on:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
      - run: npm test
Push and observe the workflow run

Your workflow file only takes effect once it reaches GitHub. Pushing to main will trigger the workflow automatically.

  • Commit and push the workflow file by running these commands:
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git push

Before you check GitHub, what do you think will happen? Will your tests pass or fail in the cloud?

  • Open your github-actions-ci-lab repository on GitHub in your browser.
  • Click the Actions tab (under your repository name).
  • In the left sidebar, click CI to see your workflow.
  • Click the workflow run (named after your commit message, "Add CI workflow").
  • Under Jobs, click the test job to expand its steps.

You should see a green check mark on the workflow run and each step (checkout, setup-node, npm test) completed successfully. Expand the Run npm test step to see your familiar test output from the cloud runner.

What just happened?

GitHub detected your push to main, found the workflow file in .github/workflows/, spun up a fresh Ubuntu VM, cloned your code, installed Node.js, and ran your tests. All within seconds, with zero manual intervention.

This is the core value of CI/CD. Every push is automatically verified, so broken code never sneaks through unnoticed.

Don't see the Actions tab?

  • Make sure your repository is public. GitHub Actions is free and enabled by default for public repositories.
  • If the tab is missing, go to Settings then Actions then General and make sure Allow all actions and reusable workflows is selected.
  • If you see a red X instead of a green check, click into the failed job and expand the failing step to read the error message.

Help me debug my GitHub Actions workflow run

Your CI pipeline is live. Every push to main now runs your tests automatically in the cloud. Next up, you'll make it even more powerful by testing across multiple Node.js versions and caching dependencies for faster builds.

Add Matrix Builds and Caching

Your CI workflow catches test failures on every push. But it only tests against one version of Node.js.

Code that passes on Node 22 can silently break on Node 20. A matrix strategy runs your tests across multiple versions in parallel, catching compatibility issues before they reach production. You'll also add dependency caching so the extra builds don't waste time re-downloading packages every run.

In this step, get ready to:
  • Add a matrix strategy to test across Node 20 and Node 22 simultaneously.
  • Cache npm dependencies so subsequent runs are faster.
  • Verify two parallel jobs run with green checks in the Actions tab.
Add a matrix strategy

Right now your workflow hardcodes node-version: 22. A matrix strategy tells GitHub Actions to spawn a separate job for each version you list, running them all in parallel.

  • In VS Code, open .github/workflows/ci.yml.
  • Update everything above your steps: entries to match this:
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20, 22]
    steps:

What changed here?

  • pull_request was added to the on: block so the workflow also fires when someone opens a PR against main.
  • strategy.matrix.node-version: [20, 22] tells GitHub Actions to create a separate job for each version in the list.
  • The matrix runs these jobs in parallel, so testing two versions takes roughly the same wall-clock time as testing one.
  • Now find the node-version: 22 line inside the with: block:
          node-version: 22
  • Replace 22 with the matrix expression so the line reads:
          node-version: ${{ matrix.node-version }}

What does this expression do?

${{ matrix.node-version }} is a GitHub Actions expression. At runtime, each parallel job substitutes its own value from the matrix list. Job 1 gets 20, job 2 gets 22.

  • Save ci.yml.
  • The GitHub Actions extension validates your YAML on save. Confirm you see no red or yellow squiggly underlines in the editor.

Seeing a red squiggly underline?

Check your indentation. YAML is whitespace-sensitive. The strategy: key must be at the same indent level as runs-on: (4 spaces). The matrix: key is 6 spaces, and node-version: inside it is 8 spaces.

help me fix the indentation in my ci.yml workflow file

Add dependency caching

Each matrix job currently downloads npm packages from scratch. The actions/setup-node action has a built-in cache option that stores downloaded packages between runs, keyed to your package-lock.json hash.

  • In ci.yml, find the steps: section and replace it with this updated version:
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test

What changed in the steps?

  • cache: 'npm' tells actions/setup-node to cache npm's global package data based on the hash of package-lock.json. On subsequent runs, packages are restored from cache instead of re-downloaded.
  • npm ci replaces the implicit install. It installs dependencies strictly from the lockfile, which is faster and guarantees reproducible builds. It also requires package-lock.json to exist (you generated this in Step 1).
  • npm test runs as a separate step so you can see install time vs test time independently in the logs.
  • Save ci.yml.
  • Confirm the extension still shows no validation errors.

Extension showing a warning about the cache key?

Make sure cache: 'npm' is at the same indent level as node-version: (both inside the with: block, indented 10 spaces from the left margin). Also confirm your project has a package-lock.json file in the repository root. Without it, the cache step will fail at runtime.

help me fix the cache configuration in my GitHub Actions workflow

Push and verify the matrix
  • Commit and push your updated workflow by running these commands:
git add .github/workflows/ci.yml
git commit -m "Add matrix strategy and dependency caching"
git push

Before you check the Actions tab, predict: how many jobs do you expect to see running, and why?

  • Open your repository on GitHub.
  • Click the Actions tab.
  • Click into the latest workflow run to see the job list.

You should see TWO separate jobs listed: test (20) and test (22). Both run in parallel, and both should show green check marks once they complete.

How do I confirm caching is working?

On your first push with the cache option, the cache is created but not yet restored (there's nothing saved from a previous run). Push a second trivial commit to see the difference.

  • Make a small change (such as editing the description in package.json), commit, and push again.
  • In the second run's logs, click into either job, expand the Setup Node.js environment step, and look for a Cache hit or Cache restored message.

Only seeing one job, or seeing a red X?

  • If you see only one job, confirm that strategy: and matrix: are correctly indented under the test: job (not under steps:).
  • If you see a red X with a npm ci error, make sure package-lock.json is committed and pushed to your repository.
  • If the error mentions a YAML syntax issue, click the error to see the line number, then compare your file to the full code reference below.

help me debug my GitHub Actions matrix workflow that isn't running correctly

✔️ Awesome, I've got everything!

Great. Confirm you've saved ci.yml and both matrix jobs passed with green checks.

ⓧ I'd like to double check the full code

Here is the complete ci.yml as it should look at the end of this step:

name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20, 22]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test

Your workflow now tests across two Node.js versions in parallel and caches dependencies between runs. Next up, you'll lock down the workflow's permissions so it follows security best practices.

Secure Your Pipeline

Your multi-version matrix is running and caching dependencies across Node 20 and 22. Subsequent runs are faster thanks to the restored cache.

There is a security gap lurking in your workflow. Without an explicit permissions block, the GITHUB_TOKEN can default to broad access depending on your repository settings. If a compromised third-party action runs inside your pipeline, it could modify your code, create releases, or exfiltrate secrets.

In this step, get ready to:
  • Add a top-level permissions block to enforce least-privilege access.
  • Add concurrency controls to cancel redundant workflow runs.
  • Push and verify the workflow still passes with restricted permissions.
Add a top-level permissions block

Every GitHub Actions workflow gets an automatic GITHUB_TOKEN that authenticates actions on your behalf. By explicitly declaring the permissions your workflow needs, you lock out everything it does not.

  • In VS Code, open .github/workflows/ci.yml.
  • Find the blank line between the on: block and the jobs: block.
  • Add the following permissions block in that gap:
permissions:
  contents: read

What does this do?

The permissions key restricts the GITHUB_TOKEN to only the scopes you list. Any scope you do not list is automatically denied (except metadata, which always has read access).

Your CI workflow only needs to check out the code and run tests. Read access to contents is all it takes.

Add concurrency controls

When you push several commits quickly, each one triggers a separate workflow run. The earlier runs are already stale, so letting them finish wastes your free-tier minutes for no reason.

  • Directly below the permissions: block you just added (and above jobs:), add the following concurrency block:
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

What does this do?

The group key creates a named lane for runs on the same branch. When a new run starts in that group, cancel-in-progress: true automatically cancels any run already in progress for the same branch.

This means only your latest push gets a full run. Stale runs are discarded immediately.

Why does the exam test this?

Concurrency controls fall under Domain 5 of the GH-200 certification (Secure and Optimize Automation). They prevent wasted compute and keep your Actions tab clean.

  • Save ci.yml.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before pushing.

ⓧ I'd like to double check the full code

name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

permissions:
  contents: read

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20, 22]
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test
Push and verify security is in place

Time to confirm your locked-down workflow still passes. A common worry is that restricting permissions will break something.

  • Commit and push the updated workflow by running these commands:
git add .github/workflows/ci.yml
git commit -m "Secure workflow with permissions and concurrency"
git push

Before you check the Actions tab, predict: will both matrix jobs still pass with read-only permissions, or will something break?

  • Open your repository on GitHub.
  • Click the Actions tab.
  • Click into the latest workflow run.

Both matrix jobs (Node 20, Node 22) should show green check marks. Your workflow only checks out code and runs tests, so read-only access is all it needs.

Test concurrency cancellation

To see cancellation in action, push two commits within a few seconds of each other. The first run will show a "cancelled" status while the second run completes normally.

Seeing a failed workflow run?

Check that permissions: is at the top level of the file (same indentation as on: and jobs:), not nested inside jobs:.

Make sure contents: read is indented two spaces under permissions:. YAML is whitespace-sensitive, so an extra space or a tab character can cause a syntax error.

help me debug my workflow permissions error

Your pipeline is now production-grade. It tests across multiple Node versions, caches dependencies, and follows the principle of least privilege. Next up, the Secret Mission challenges you to add manual triggers and artifact uploads.

Secret mission

Add Manual Triggers and Artifact Uploads

Your CI pipeline runs automatically on every push. But what about debugging a single Node version on demand? Or saving test output for later inspection? Real-world pipelines need both manual triggers and artifact storage. This secret mission adds workflow_dispatch inputs and upload-artifact to your workflow.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally and on GitHub's free tier, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • GitHub repository github-actions-ci-lab
  • Local project folder github-actions-ci-lab on your Desktop.
  • GitHub Actions VS Code extension.

Keep everything running

No action needed. Choose this if you plan to keep experimenting with GitHub Actions workflows or want a reference project to revisit.

  • Your repository stays public and free with unlimited Actions minutes.
  • Your local files stay on your Desktop ready for editing.
  • The GitHub Actions VS Code extension stays installed for future workflow editing.

Pause - I'll come back to this later

Free up local disk space while keeping your remote repository intact. You can always clone it again later.

  • Close the project in VS Code.
  • Delete the local folder from your Desktop. Your GitHub repository still holds all your code.
  • When you want to resume, clone the repository again and pick up where you left off.

Delete - I don't want to use this again

Remove all project resources from your machine and GitHub account.

  • Delete the local project folder by running one of these commands in your terminal:

macOS

rm -rf ~/Desktop/github-actions-ci-lab

Windows

Remove-Item -Recurse -Force ~\Desktop\github-actions-ci-lab
  • Delete the GitHub repository:
  • Go to your github-actions-ci-lab repository on GitHub.
  • Click Settings in the repository navigation bar.
  • Scroll down to the Danger Zone section and click Delete this repository.
  • Click I want to delete this repository.
  • Click I have read and understand these effects.
  • Type the repository name to confirm, then click Delete this repository.
  • Uninstall the GitHub Actions VS Code extension by running:
code --uninstall-extension GitHub.vscode-github-actions

What about Node.js?

Node.js is a general-purpose tool you will likely use in other projects. There is no need to uninstall it unless you specifically want to remove it from your system.

That's a Wrap!

That's a Wrap!

Nice work! You just built a production-grade CI pipeline from scratch using GitHub Actions.

You've learned how to:

  • Author a CI workflow from scratch using GitHub Actions YAML syntax, including triggers, jobs, and steps that automatically test your code on every push and pull request.
  • Use a matrix strategy to test across multiple Node.js versions simultaneously, with dependency caching to keep builds fast.
  • Harden your pipeline with least-privilege permissions and concurrency controls that prevent wasted runner minutes and limit the blast radius of compromised actions.
  • Added workflow_dispatch with custom inputs for manual triggering and uploaded test artifacts for later inspection.

Ready to quiz yourself?