Skip to content

CI/CD Pipeline

CI/CD Pipeline #263

Workflow file for this run

name: CI/CD Pipeline
# Workflow triggers
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Schedule pipeline to run monday midnight after sunday ends
schedule:
- cron: 0 0 * * MON
# Enable manual runs of workflow
workflow_dispatch:
# Workflow stages
jobs:
# Perform Lint Checks
lint:
name: Style and Lint Checks
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Install pnpm
run: npm install -g pnpm
- name: Install Dependencies
run: pnpm install
- name: Run lint script
run: pnpm run lint
# Run Unit Tests
test:
name: Unit Tests
needs: lint
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install
- name: Run unit tests with jest
run: pnpm run test
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# Build Application
build:
name: Build Application
needs: test
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Install pnpm
run: npm install -g pnpm
- name: Install Dependencies
run: pnpm install
- name: Compile TypeScript into JavaScript
run: pnpm run build
# Detect if there were code changes on PR and push and save the result to:
# - File artifact (since environment variables are limited to the scope they're created in)
detect-code-changes:
name: Detect Code Changes
if: github.event_name == 'push' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs: build
steps:
# Get changed files
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44.5.1
- name: Set CHANGED_FILES as environment variable
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: echo "CHANGED_FILES=${{ steps.changed-files.outputs.all_changed_files }}" >> $GITHUB_ENV
# Get non .md and non-pipeline changes
- name: Check for non-Markdown and non-pipeline changes
run: |
NON_MD_PIPELINE_CHANGES=$(echo "$CHANGED_FILES" | tr ' ' '\n' | grep -vE '(\.md$|\.github/)' || echo '')
if [ -n "$NON_MD_PIPELINE_CHANGES" ]; then
echo "true" > code_changes.txt
else
echo "false" > code_changes.txt
fi
- name: Upload code_changes.txt as an artifact
uses: actions/upload-artifact@v4
with:
name: code-changes-artifact
path: code_changes.txt
# Check if CHANGELOG.md is updated and push to artifact
- name: Check if CHANGELOG.md is updated
run: |
if echo "$CHANGED_FILES" | tr ' ' '\n' | grep -q 'CHANGELOG.md'; then
echo "true" > changelog_updated.txt
else
echo "false" > changelog_updated.txt
fi
- name: Upload changelog_updated.txt as an artifact
uses: actions/upload-artifact@v4
with:
name: changelog-changes-artifact
path: changelog_updated.txt
# Verify new NPM version is updated during push and PR.
# Skips version number check step if there were code changes
verify-npm-version:
name: Verify Updated Version and Changelog (if code changed)
if: github.event_name == 'push' || github.event_name == 'pull_request'
needs: detect-code-changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetches all history for all branches and tags
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org/'
- name: Install dependencies
run: npm install
# Check if there were version number updates if code changed
- uses: actions/download-artifact@v4
with:
name: code-changes-artifact
- name: Read Code Changes Flag From Artifact
run: |
echo "CODE_CHANGES=$(cat code_changes.txt)" >> $GITHUB_ENV
- name: Check if version number is updated
if: env.CODE_CHANGES == 'true'
run: |
LATEST_TAG=$(git describe --tags --abbrev=0)
PACKAGE_VERSION=$(node -p "require('./package.json').version")
if [ "$LATEST_TAG" = "v$PACKAGE_VERSION" ]; then
echo "Version in package.json is already published. Exiting..."
exit 1
fi
# Check if there were changelog changes if code changed
- uses: actions/download-artifact@v4
with:
name: changelog-changes-artifact
- name: Read Code Changes Flag From Artifact
run: |
echo "CHANGELOG_UPDATED=$(cat changelog_updated.txt)" >> $GITHUB_ENV
- name: Check if changelog is updated
if: env.CODE_CHANGES == 'true'
run: |
if [ "$CHANGELOG_UPDATED" != "true" ]; then
echo "Failure: Changelog must be updated for new releases."
exit 1
fi
# Publish to NPM if the event was 'push'.
# Runs the publish to NPM step only if there were code changes
publish-npm:
name: Publish to NPM (if code changed)
if: github.event_name == 'push'
needs: verify-npm-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetches all history for all branches and tags
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org/'
- name: Install pnpm
run: npm install -g pnpm
- name: Install Dependencies
run: pnpm install
- uses: actions/download-artifact@v4
with:
name: code-changes-artifact # get artifact containing whether there were code changes
- name: Read Code Changes Flag From Artifact
run: |
echo "CODE_CHANGES=$(cat code_changes.txt)" >> $GITHUB_ENV
- name: Get package version number
run: echo "PACKAGE_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Build TypeScript into JavaScript build artifact
run: pnpm run build
- name: Publish to NPM # only run if there were code changes
if: env.CODE_CHANGES == 'true' && env.PACKAGE_VERSION
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# Create Release on GitHub if the event was 'push'.
# Runs the release step only if there were code changes
release:
name: Create Release (if code changed)
if: github.event_name == 'push'
needs: verify-npm-version
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: code-changes-artifact # get artifact containing whether there were code changes
- name: Read Code Changes Flag From Artifact
run: |
echo "CODE_CHANGES=$(cat code_changes.txt)" >> $GITHUB_ENV
- name: Extract version number
run: echo "RELEASE_VERSION=$(jq -r .version package.json)" >> $GITHUB_ENV
- name: Create Release # only run if there were code changes
if: env.CODE_CHANGES == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "v$RELEASE_VERSION" \
--repo="$GITHUB_REPOSITORY" \
--title="v${RELEASE_VERSION#v}" \
--generate-notes