Skip to content

Instantly share code, notes, and snippets.

@decebal
Created May 7, 2025 10:37
Show Gist options
  • Save decebal/3fc806ef3612041d442c939f0db823db to your computer and use it in GitHub Desktop.
Save decebal/3fc806ef3612041d442c939f0db823db to your computer and use it in GitHub Desktop.
Detect changes in monorepos setup based on midday-ai/v1
name: Detect Changes
on:
workflow_call:
outputs:
HAS_APP_CHANGES:
description: "Whether app has changes"
value: ${{ jobs.detect-changes.outputs.HAS_APP_CHANGES }}
HAS_WEB_CHANGES:
description: "Whether web has changes"
value: ${{ jobs.detect-changes.outputs.HAS_WEB_CHANGES }}
HAS_BACKEND_CHANGES:
description: "Whether backend has changes"
value: ${{ jobs.detect-changes.outputs.HAS_BACKEND_CHANGES }}
CHANGED_APPS:
description: "List of changed apps"
value: ${{ jobs.detect-changes.outputs.AFFECTED_PROJECTS }}
jobs:
# 🔍 Detect which packages have changed to determine if we need to deploy
detect-changes:
runs-on: ubuntu-latest
outputs:
HAS_APP_CHANGES: ${{ steps.turbo-changes.outputs.HAS_APP_CHANGES }}
HAS_WEB_CHANGES: ${{ steps.turbo-changes.outputs.HAS_WEB_CHANGES }}
HAS_BACKEND_CHANGES: ${{ steps.turbo-changes.outputs.HAS_BACKEND_CHANGES }}
AFFECTED_PROJECTS: ${{ steps.turbo-changes.outputs.AFFECTED_PROJECTS }}
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🧰 Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: 📦 Install dependencies
run: bun install
- name: 🔍 Detect Changes with Turbo
id: turbo-changes
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
TURBO_TOKEN: ${{ secrets.VERCEL_TOKEN }}
TURBO_TEAM: "alphasigmapros-projects"
run: |
echo "📊 Analyzing repository changes..."
chmod +x ./tooling/ops/helpers/turbo-detect-changes.sh
./tooling/ops/helpers/turbo-detect-changes.sh main
#!/bin/bash
# tooling/ops/helpers/turbo-detect-changes.sh
# Script to detect changes in the monorepo using git diff and Turborepo
# Usage: ./turbo-detect-changes.sh [base-branch]
# Example: ./turbo-detect-changes.sh main
set -e
# Default base branch is main if not provided
BASE_BRANCH=${1:-main}
# Check if we're in a git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: Not in a git repository"
exit 1
fi
# Ensure we have the latest changes from the base branch
echo "Fetching latest changes from $BASE_BRANCH..."
git fetch origin $BASE_BRANCH --quiet
# Improved change detection for both regular and squashed merges
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
# For pull requests, compare against the PR base
echo "Pull request detected, comparing against PR base..."
COMPARE_AGAINST="origin/$BASE_BRANCH"
else
# For direct pushes to main or after squash merges
# Get the last commit on the base branch before the current HEAD
echo "Push to $BASE_BRANCH detected, using commit comparison..."
COMPARE_AGAINST="origin/$BASE_BRANCH"
# If we're on main, compare the current commit with the previous commit
if [ "$(git rev-parse --abbrev-ref HEAD)" = "$BASE_BRANCH" ]; then
echo "On $BASE_BRANCH branch, comparing with previous commit..."
COMPARE_AGAINST="HEAD~1"
fi
fi
echo "Comparing changes between $COMPARE_AGAINST and HEAD"
# Use git diff to detect changes with shell-functools
echo "Detecting changes using git diff..."
# Function to check for changes in a specific directory
check_changes() {
local dir=$1
local changes=$(git diff --name-only $COMPARE_AGAINST HEAD -- "$dir" || true)
if [ -n "$changes" ]; then
echo "Changes detected in $dir"
return 0
else
echo "No changes detected in $dir"
return 1
fi
}
# Use shell-functools to process the list of changed files
get_changed_files() {
local dir=$1
git diff --name-only $COMPARE_AGAINST HEAD -- "$dir" | sort | uniq || echo ""
}
# Check for changes in different parts of the monorepo
WEB_CHANGES=$(get_changed_files "apps/web/")
APP_CHANGES=$(get_changed_files "apps/app/")
BACKEND_CHANGES=$(get_changed_files "apps/backend/")
API_CHANGES=$(get_changed_files "apps/api/")
SHARED_CHANGES=$(get_changed_files "packages/ tooling/")
# Determine if there are changes in each app using shell-functools
has_changes() {
local changes=$1
local shared=$2
if [ -n "$changes" ] || [ -n "$shared" ]; then
return 0
else
return 1
fi
}
if has_changes "$WEB_CHANGES" "$SHARED_CHANGES"; then
echo "Changes detected in web app"
HAS_WEB_CHANGES=1
else
echo "No changes detected in web app"
HAS_WEB_CHANGES=0
fi
if has_changes "$APP_CHANGES" "$SHARED_CHANGES"; then
echo "Changes detected in app"
HAS_APP_CHANGES=1
else
echo "No changes detected in app"
HAS_APP_CHANGES=0
fi
if has_changes "$BACKEND_CHANGES" "$SHARED_CHANGES"; then
echo "Changes detected in backend"
HAS_BACKEND_CHANGES=1
else
echo "No changes detected in backend"
HAS_BACKEND_CHANGES=0
fi
if has_changes "$API_CHANGES" "$SHARED_CHANGES"; then
echo "Changes detected in API"
HAS_API_CHANGES=1
else
echo "No changes detected in API"
HAS_API_CHANGES=0
fi
# Now let's use Turbo to determine the affected projects based on dependencies
echo "Analyzing dependencies with Turborepo..."
# Build filter string using shell-functools
build_filter() {
local result=""
local apps=("$@")
for app in "${apps[@]}"; do
if [ -n "$result" ]; then
result="$result,$app"
else
result="$app"
fi
done
echo "$result"
}
# Get the list of affected projects
if [ -n "$SHARED_CHANGES" ]; then
echo "Shared packages changed, all projects may be affected"
AFFECTED_PROJECTS="@v1/web,@v1/app,@v1/backend,@v1/api"
else
# Build the filter string for Turbo
AFFECTED_APPS=()
if [ "$HAS_WEB_CHANGES" -eq 1 ]; then
AFFECTED_APPS+=("@v1/web")
fi
if [ "$HAS_APP_CHANGES" -eq 1 ]; then
AFFECTED_APPS+=("@v1/app")
fi
if [ "$HAS_BACKEND_CHANGES" -eq 1 ]; then
AFFECTED_APPS+=("@v1/backend")
fi
if [ "$HAS_API_CHANGES" -eq 1 ]; then
AFFECTED_APPS+=("@v1/api")
fi
AFFECTED_PROJECTS=$(build_filter "${AFFECTED_APPS[@]}")
fi
echo "Affected projects: $AFFECTED_PROJECTS"
# Determine if any frontend apps have changes
FRONTEND_APPS=()
if [ "$HAS_WEB_CHANGES" -eq 1 ]; then
FRONTEND_APPS+=("@v1/web")
fi
if [ "$HAS_APP_CHANGES" -eq 1 ]; then
FRONTEND_APPS+=("@v1/app")
fi
if [ ${#FRONTEND_APPS[@]} -gt 0 ]; then
HAS_FRONTEND_CHANGES=1
FRONTEND_APPS_STR=$(build_filter "${FRONTEND_APPS[@]}")
echo "Frontend changes detected"
echo "Frontend apps with changes: $FRONTEND_APPS_STR"
else
HAS_FRONTEND_CHANGES=0
FRONTEND_APPS_STR=""
echo "No frontend changes detected"
fi
# Determine if any backend apps have changes
BACKEND_APPS=()
if [ "$HAS_BACKEND_CHANGES" -eq 1 ]; then
BACKEND_APPS+=("@v1/backend")
fi
if [ "$HAS_API_CHANGES" -eq 1 ]; then
BACKEND_APPS+=("@v1/api")
fi
if [ ${#BACKEND_APPS[@]} -gt 0 ]; then
HAS_BACKEND_CHANGES=1
BACKEND_APPS_STR=$(build_filter "${BACKEND_APPS[@]}")
echo "Backend changes detected"
echo "Backend apps with changes: $BACKEND_APPS_STR"
else
HAS_BACKEND_CHANGES=0
BACKEND_APPS_STR=""
echo "No backend changes detected"
fi
# Output for GitHub Actions
if [ -n "$GITHUB_OUTPUT" ]; then
echo "HAS_FRONTEND_CHANGES=${HAS_FRONTEND_CHANGES}" >> $GITHUB_OUTPUT
echo "HAS_BACKEND_CHANGES=${HAS_BACKEND_CHANGES}" >> $GITHUB_OUTPUT
echo "HAS_WEB_CHANGES=${HAS_WEB_CHANGES}" >> $GITHUB_OUTPUT
echo "HAS_APP_CHANGES=${HAS_APP_CHANGES}" >> $GITHUB_OUTPUT
echo "FRONTEND_APPS=${FRONTEND_APPS_STR}" >> $GITHUB_OUTPUT
echo "BACKEND_APPS=${BACKEND_APPS_STR}" >> $GITHUB_OUTPUT
echo "AFFECTED_PROJECTS=${AFFECTED_PROJECTS}" >> $GITHUB_OUTPUT
fi
# Return success if any changes were detected
if [ "$HAS_FRONTEND_CHANGES" -eq 1 ] || [ "$HAS_BACKEND_CHANGES" -eq 1 ]; then
echo "Changes detected, should deploy"
exit 0
else
echo "No changes detected, no need to deploy"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment