8383 restore-keys : |
8484 ${{ runner.os }}-${{ runner.arch }}-yarn-
8585
86+ - name : Debug cache contents
87+ id : debug-cache
88+ if : ${{ !env.ACT && steps.yarn-cache.outputs.cache-hit == 'true' }}
89+ shell : bash
90+ run : |
91+ set +e # Don't exit on error - we want to continue even if find fails
92+
93+ echo "=== 🔍 Cache Debug Info ==="
94+ echo "Cache key: ${{ runner.os }}-${{ runner.arch }}-yarn-${{ hashFiles('**/yarn.lock', '**/package.json') }}"
95+ echo ""
96+
97+ echo "=== 📦 Root node_modules Status ==="
98+ if [ -d "node_modules" ]; then
99+ MODULE_COUNT=$(ls -1 node_modules 2>/dev/null | wc -l | tr -d ' ')
100+ echo "✅ node_modules exists"
101+ echo "📊 Package count: $MODULE_COUNT"
102+ echo "🔒 Yarn integrity: $([ -f 'node_modules/.yarn-integrity' ] && echo '✅ present' || echo '❌ missing')"
103+ else
104+ echo "❌ node_modules directory not found"
105+ fi
106+ echo ""
107+
108+ echo "=== 🏢 Workspace Structure ==="
109+ # Use find with || true to prevent failures when directories don't exist
110+ WORKSPACE_PACKAGES=$(find packages/*/package.json apps/*/package.json -type f 2>/dev/null || true | wc -l | tr -d ' ')
111+ WORKSPACE_MODULES=$(find packages/*/node_modules apps/*/node_modules -maxdepth 0 -type d 2>/dev/null || true | wc -l | tr -d ' ')
112+ echo "📦 Workspace packages: $WORKSPACE_PACKAGES"
113+ echo "🔗 Workspace node_modules: $WORKSPACE_MODULES"
114+
115+ if [ "$WORKSPACE_PACKAGES" -gt 0 ]; then
116+ echo ""
117+ echo "Workspace packages found:"
118+ find packages/*/package.json apps/*/package.json -type f 2>/dev/null || true | sed 's|/package.json||' | sed 's|^| - |'
119+ fi
120+ echo ""
121+
122+ set -e # Re-enable exit on error
123+
86124 - name : Check if yarn install needed on cache hit
87125 id : check-install-needed
88126 if : ${{ !env.ACT }}
@@ -94,48 +132,103 @@ runs:
94132 # - Cache restores node_modules, but doesn't run postinstall hooks
95133 # - Monorepos need workspace linking even with cached node_modules
96134 # - Some projects have critical postinstall scripts (e.g., building native modules)
135+ # - Cached node_modules might be incomplete or corrupted
97136 #
98- # We detect three scenarios that require yarn install on cache hit:
137+ # We detect scenarios that require yarn install on cache hit:
99138
100139 NEEDS_INSTALL=false
140+ CACHE_HIT="${{ steps.yarn-cache.outputs.cache-hit }}"
101141
102- # 1. Yarn workspaces: Need symlink creation between workspace packages
103- if grep -q '"workspaces"' package.json 2>/dev/null; then
104- echo "📦 Detected Yarn workspaces - install needed for workspace linking"
105- NEEDS_INSTALL=true
106- fi
107-
108- # 2. Lerna monorepo: Need lerna bootstrap (usually in postinstall hook)
109- if [ -f "lerna.json" ]; then
110- echo "📦 Detected Lerna monorepo - install needed for lerna bootstrap"
111- NEEDS_INSTALL=true
142+ # On cache hit, verify cache integrity before trusting it
143+ if [ "$CACHE_HIT" == "true" ]; then
144+ echo "=== 🔍 Verifying Cache Integrity ==="
145+
146+ # Verification 1: Check if node_modules exists and has content
147+ if [ ! -d "node_modules" ]; then
148+ echo "❌ node_modules directory missing - forcing install"
149+ NEEDS_INSTALL=true
150+ else
151+ MODULE_COUNT=$(ls -1 node_modules 2>/dev/null | wc -l | tr -d ' ')
152+ if [ "$MODULE_COUNT" -lt 5 ]; then
153+ echo "⚠️ node_modules appears empty ($MODULE_COUNT packages) - forcing install"
154+ NEEDS_INSTALL=true
155+ fi
156+ fi
157+
158+ # Verification 2: Check yarn integrity file
159+ if [ "$NEEDS_INSTALL" == "false" ] && [ ! -f "node_modules/.yarn-integrity" ]; then
160+ echo "⚠️ Missing .yarn-integrity file - cache may be incomplete, forcing install"
161+ NEEDS_INSTALL=true
162+ fi
163+
164+ # Verification 3: For workspaces, verify workspace packages have node_modules
165+ if [ "$NEEDS_INSTALL" == "false" ]; then
166+ WORKSPACE_PACKAGES=$(find packages/*/package.json apps/*/package.json -type f 2>/dev/null || true | wc -l | tr -d ' ')
167+ if [ "$WORKSPACE_PACKAGES" -gt 0 ]; then
168+ WORKSPACE_MODULES=$(find packages/*/node_modules apps/*/node_modules -maxdepth 0 -type d 2>/dev/null || true | wc -l | tr -d ' ')
169+ if [ "$WORKSPACE_MODULES" -eq 0 ]; then
170+ echo "⚠️ Workspace packages exist but no workspace node_modules found - forcing install"
171+ NEEDS_INSTALL=true
172+ fi
173+ fi
174+ fi
175+
176+ if [ "$NEEDS_INSTALL" == "false" ]; then
177+ echo "✅ Cache integrity verified"
178+ fi
112179 fi
113180
114- # 3. Postinstall hook: Any project with postinstall needs it executed
115- # Examples: building native modules, generating files, running setup scripts
116- if grep -q '"postinstall"' package.json 2>/dev/null; then
117- echo "🔧 Detected postinstall hook - install needed to execute it"
118- NEEDS_INSTALL=true
181+ # Check for monorepo configurations that need install
182+ if [ "$NEEDS_INSTALL" == "false" ]; then
183+ # 1. Yarn workspaces: ALWAYS need symlink creation between workspace packages
184+ # CRITICAL: Workspace symlinks are NOT preserved in GitHub Actions cache!
185+ # Even Turbo monorepos need this - Turbo handles build caching, not workspace linking.
186+ if grep -q '"workspaces"' package.json 2>/dev/null; then
187+ echo "📦 Detected Yarn workspaces - install needed for workspace linking"
188+ echo " ⚠️ Workspace symlinks are not preserved in cache"
189+ echo " ⚠️ Skipping install will cause 'module not found' errors"
190+ NEEDS_INSTALL=true
191+ fi
192+
193+ # 2. Lerna monorepo: Need lerna bootstrap (usually in postinstall hook)
194+ if [ -f "lerna.json" ]; then
195+ echo "📦 Detected Lerna monorepo - install needed for lerna bootstrap"
196+ NEEDS_INSTALL=true
197+ fi
198+
199+ # 3. Postinstall hook: Any project with postinstall needs it executed
200+ # Examples: building native modules, generating files, running setup scripts
201+ if grep -q '"postinstall"' package.json 2>/dev/null; then
202+ echo "🔧 Detected postinstall hook - install needed to execute it"
203+ NEEDS_INSTALL=true
204+ fi
119205 fi
120206
121207 echo "needs-install=$NEEDS_INSTALL" >> $GITHUB_OUTPUT
122208
123- - name : Log cache status
209+ - name : Log cache status and decision
124210 if : ${{ !env.ACT }}
125211 shell : bash
126212 run : |
213+ echo "=== 📊 Cache Status Summary ==="
127214 if [ "${{ steps.yarn-cache.outputs.cache-hit }}" == "true" ]; then
128215 echo "✅ Cache HIT - Dependencies restored from cache"
129216 echo "📦 Cache key: ${{ runner.os }}-${{ runner.arch }}-yarn-${{ hashFiles('**/yarn.lock', '**/package.json') }}"
217+ echo ""
130218 if [ "${{ steps.check-install-needed.outputs.needs-install }}" == "true" ]; then
131- echo "🔗 Will run yarn install for workspace linking and/or postinstall hooks"
219+ echo "🔄 Decision: WILL run yarn install"
220+ echo "Reasons: Cache verification failed, workspace linking needed, or postinstall hooks detected"
132221 else
133- echo "⚡ Skipping yarn install - not a monorepo and no postinstall hooks"
222+ echo "⚡ Decision: SKIP yarn install"
223+ echo "Reason: Cache verified and no workspace linking or postinstall hooks required"
134224 fi
135225 else
136- echo "❌ Cache MISS - Installing dependencies "
226+ echo "❌ Cache MISS - Fresh installation required "
137227 echo "🔍 Looking for key: ${{ runner.os }}-${{ runner.arch }}-yarn-${{ hashFiles('**/yarn.lock', '**/package.json') }}"
228+ echo ""
229+ echo "🔄 Decision: WILL run yarn install"
138230 fi
231+ echo ""
139232
140233 - name : Install Node.js dependencies
141234 if : ${{ !env.ACT && (steps.yarn-cache.outputs.cache-hit != 'true' || steps.check-install-needed.outputs.needs-install == 'true') }}
0 commit comments