Skip to content

Commit bfabc2e

Browse files
IONOS(ci): add detect-app-cache.sh — per-app JFrog + GitHub cache probe
Helper script consumed by the cached parallel matrix CI pipeline (added in the next commit). For each app emitted by IONOS/Makefile's generate_apps_matrix_json target, it computes a per-app cache key from the submodule SHA, probes JFrog Artifactory first, falls back to a GitHub Actions cache lookup via gh cache list, and writes three JSON outputs: - apps_to_build: apps whose artifact is missing and must be built - apps_to_restore: apps whose artifact exists in JFrog or GH cache - apps_sha_map: full {name: SHA} map for traceability Cache-key shape is uniform: \${CACHE_VERSION}-app-build-\${APP_NAME}-\${SHORT_SHA} (8-char short SHA). The custom-npms compound-key branch from PR #226's earlier iterations is gone — custom-npms submodules no longer exist and generate_apps_matrix_json always emits needs_custom_npms:false. JFrog setup is idempotent (jf config show short-circuits the add) and gracefully degrades to GH-cache-only when JF_URL/JF_USER/JF_ACCESS_TOKEN are absent. Signed-off-by: Misha M.-Kupriyanov <kupriyanov@strato.de>
1 parent fcd39f0 commit bfabc2e

1 file changed

Lines changed: 377 additions & 0 deletions

File tree

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
#!/bin/bash
2+
3+
# SPDX-FileCopyrightText: 2025 STRATO AG
4+
# SPDX-License-Identifier: AGPL-3.0-or-later
5+
6+
# Script to detect which apps need building vs. can be restored from cache
7+
# Supports multiple cache sources: GitHub Actions cache and JFrog Artifactory
8+
# Outputs JSON arrays for apps to build and apps to restore
9+
10+
set -e # Exit on error
11+
set -u # Exit on undefined variable
12+
set -o pipefail # Exit if any command in pipeline fails
13+
14+
# Required environment variables
15+
: "${GH_TOKEN:?GH_TOKEN not set}"
16+
: "${CACHE_VERSION:?CACHE_VERSION not set}"
17+
: "${FORCE_REBUILD:?FORCE_REBUILD not set}"
18+
: "${ARTIFACTORY_REPOSITORY_SNAPSHOT:?ARTIFACTORY_REPOSITORY_SNAPSHOT not set}"
19+
20+
# Optional variables
21+
APPS_TO_REBUILD="${APPS_TO_REBUILD:-}"
22+
JF_URL="${JF_URL:-}"
23+
JF_USER="${JF_USER:-}"
24+
JF_ACCESS_TOKEN="${JF_ACCESS_TOKEN:-}"
25+
26+
# Input: MATRIX (JSON array of app configurations)
27+
# Input: GITHUB_REF (current GitHub ref)
28+
# Input: GITHUB_STEP_SUMMARY (path to step summary file)
29+
30+
# Outputs to $GITHUB_OUTPUT:
31+
# - apps_to_build: JSON array of apps that need building
32+
# - apps_to_restore: JSON array of apps that can be restored from cache
33+
# - apps_sha_map: JSON object mapping app names to their SHAs
34+
# - has_apps_to_build: boolean flag
35+
# - has_apps_to_restore: boolean flag
36+
37+
echo "Collecting app SHAs and checking cache status..."
38+
echo "Cache version: $CACHE_VERSION"
39+
echo "Force rebuild mode: $FORCE_REBUILD"
40+
if [ -n "$APPS_TO_REBUILD" ]; then
41+
echo "Apps to rebuild: $APPS_TO_REBUILD"
42+
fi
43+
echo ""
44+
45+
# Setup JFrog CLI if credentials are available
46+
JFROG_AVAILABLE="false"
47+
echo "=== JFrog Setup ==="
48+
echo "JF_URL present: $([ -n "$JF_URL" ] && echo 'YES' || echo 'NO')"
49+
echo "JF_USER present: $([ -n "$JF_USER" ] && echo 'YES' || echo 'NO')"
50+
echo "JF_ACCESS_TOKEN present: $([ -n "$JF_ACCESS_TOKEN" ] && echo 'YES' || echo 'NO')"
51+
52+
if [ -n "$JF_URL" ] && [ -n "$JF_USER" ] && [ -n "$JF_ACCESS_TOKEN" ]; then
53+
echo "✓ All JFrog credentials available"
54+
if ! command -v jf >/dev/null 2>&1; then
55+
echo "⚠ JFrog CLI (jf) not in PATH; skipping JFrog cache checks"
56+
echo " (jf should be installed by jfrog/setup-jfrog-cli before this script runs)"
57+
else
58+
echo "JFrog CLI version: $(jf --version)"
59+
60+
# Configure JFrog (skip if already configured — avoids "Server ID already exists" when
61+
# a previous step in the same job has already run jf config add with the same server ID)
62+
if jf config show jfrog-server >/dev/null 2>&1; then
63+
echo "JFrog server 'jfrog-server' already configured, reusing"
64+
else
65+
echo "Configuring JFrog server: $JF_URL"
66+
jf config add jfrog-server --url="$JF_URL" --user="$JF_USER" --access-token="$JF_ACCESS_TOKEN" --interactive=false
67+
fi
68+
69+
# Test connection with verbose output
70+
echo "Testing JFrog connection..."
71+
if jf rt ping; then
72+
JFROG_AVAILABLE="true"
73+
echo "✓ JFrog connection successful"
74+
echo "Repository: $ARTIFACTORY_REPOSITORY_SNAPSHOT"
75+
else
76+
echo "⚠ JFrog ping failed, will fall back to GitHub cache"
77+
fi
78+
fi
79+
else
80+
echo "⚠ JFrog credentials not available, using GitHub cache only"
81+
[ -z "$JF_URL" ] && echo " - Missing: JF_URL"
82+
[ -z "$JF_USER" ] && echo " - Missing: JF_USER"
83+
[ -z "$JF_ACCESS_TOKEN" ] && echo " - Missing: JF_ACCESS_TOKEN"
84+
fi
85+
echo "JFROG_AVAILABLE=$JFROG_AVAILABLE"
86+
echo "==================="
87+
echo ""
88+
89+
# Get the matrix from input (passed as argument)
90+
MATRIX="$1"
91+
92+
# Build JSON arrays for apps that need building/restoring
93+
APPS_TO_BUILD="[]"
94+
APPS_TO_RESTORE="[]"
95+
APPS_CHECKED=0
96+
APPS_CACHED=0
97+
APPS_IN_JFROG=0
98+
APPS_TO_BUILD_COUNT=0
99+
APPS_TO_RESTORE_COUNT=0
100+
APPS_SHA_MAP="{}"
101+
echo ""
102+
103+
echo "### 📦 Cache Status Report for ($GITHUB_REF)" >> "$GITHUB_STEP_SUMMARY"
104+
echo "" >> "$GITHUB_STEP_SUMMARY"
105+
echo "**Cache Version:** \`$CACHE_VERSION\`" >> "$GITHUB_STEP_SUMMARY"
106+
echo "" >> "$GITHUB_STEP_SUMMARY"
107+
if [ "$FORCE_REBUILD" == "true" ]; then
108+
echo "**🔄 FORCE REBUILD MODE ENABLED** - All caches bypassed" >> "$GITHUB_STEP_SUMMARY"
109+
echo "" >> "$GITHUB_STEP_SUMMARY"
110+
fi
111+
if [ -n "$APPS_TO_REBUILD" ]; then
112+
echo "**🔨 Specific apps to rebuild:** \`$APPS_TO_REBUILD\`" >> "$GITHUB_STEP_SUMMARY"
113+
echo "" >> "$GITHUB_STEP_SUMMARY"
114+
fi
115+
if [ "$JFROG_AVAILABLE" == "true" ]; then
116+
echo "**🎯 JFrog Artifact Cache**: Enabled for all branches" >> "$GITHUB_STEP_SUMMARY"
117+
echo "" >> "$GITHUB_STEP_SUMMARY"
118+
fi
119+
echo "| App | SHA | Cache Key | Status |" >> "$GITHUB_STEP_SUMMARY"
120+
echo "|-----|-----|-----------|--------|" >> "$GITHUB_STEP_SUMMARY"
121+
122+
# Convert comma-separated apps list to array for easier checking
123+
if [ -n "$APPS_TO_REBUILD" ]; then
124+
IFS=',' read -ra REBUILD_APPS_ARRAY <<< "$APPS_TO_REBUILD"
125+
# Trim whitespace from each app name using xargs for readability
126+
for i in "${!REBUILD_APPS_ARRAY[@]}"; do
127+
REBUILD_APPS_ARRAY[$i]=$(echo "${REBUILD_APPS_ARRAY[$i]}" | xargs)
128+
done
129+
else
130+
REBUILD_APPS_ARRAY=()
131+
fi
132+
133+
# Iterate through each app in the matrix
134+
while IFS= read -r app_json; do
135+
APP_NAME=$(echo "$app_json" | jq -r '.name')
136+
APP_PATH=$(echo "$app_json" | jq -r '.path')
137+
138+
APPS_CHECKED=$((APPS_CHECKED + 1))
139+
140+
# Get current submodule SHA
141+
if [ -d "$APP_PATH" ]; then
142+
CURRENT_SHA=$(git -C "$APP_PATH" rev-parse HEAD 2>/dev/null || echo "")
143+
else
144+
echo "$APP_NAME - directory not found at '$APP_PATH' (submodule not initialised?), will build"
145+
echo "| $APP_NAME | N/A | N/A | ⊘ Directory not found — will build |" >> "$GITHUB_STEP_SUMMARY"
146+
UNKNOWN_SUFFIX="unknown"
147+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
148+
--arg app "$APP_NAME" --arg sha "$UNKNOWN_SUFFIX" \
149+
--arg archive_name "${APP_NAME}-${UNKNOWN_SUFFIX}.tar.gz" \
150+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${UNKNOWN_SUFFIX}.tar.gz" \
151+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
152+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
153+
continue
154+
fi
155+
156+
if [ -z "$CURRENT_SHA" ]; then
157+
echo "$APP_NAME - '$APP_PATH' exists but is not a git repo, will build"
158+
echo "| $APP_NAME | N/A | N/A | ⊘ Not a git repo — will build |" >> "$GITHUB_STEP_SUMMARY"
159+
UNKNOWN_SUFFIX="unknown"
160+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
161+
--arg app "$APP_NAME" --arg sha "$UNKNOWN_SUFFIX" \
162+
--arg archive_name "${APP_NAME}-${UNKNOWN_SUFFIX}.tar.gz" \
163+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${UNKNOWN_SUFFIX}.tar.gz" \
164+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
165+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
166+
continue
167+
fi
168+
169+
# Add SHA to the map for all apps (regardless of cache status)
170+
APPS_SHA_MAP=$(echo "$APPS_SHA_MAP" | jq -c --arg app "$APP_NAME" --arg sha "$CURRENT_SHA" '.[$app] = $sha')
171+
172+
# Cache key for this app — use 8-char short SHAs throughout.
173+
SHORT_SHA="${CURRENT_SHA:0:8}"
174+
CACHE_KEY="${CACHE_VERSION}-app-build-${APP_NAME}-${SHORT_SHA}"
175+
ARCHIVE_SUFFIX="${SHORT_SHA}"
176+
177+
echo -n " Checking $APP_NAME (SHA: $SHORT_SHA)... "
178+
179+
# If force rebuild is enabled, skip cache check and rebuild everything
180+
if [ "$FORCE_REBUILD" == "true" ]; then
181+
echo "🔄 force rebuild"
182+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$CACHE_KEY\` | 🔄 Force rebuild |" >> "$GITHUB_STEP_SUMMARY"
183+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
184+
--arg app "$APP_NAME" --arg sha "$CURRENT_SHA" \
185+
--arg archive_name "${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
186+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
187+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
188+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
189+
continue
190+
fi
191+
192+
# Check if this specific app should be rebuilt (ignore cache)
193+
REBUILD_THIS_APP=false
194+
for rebuild_app in "${REBUILD_APPS_ARRAY[@]}"; do
195+
if [ "$APP_NAME" == "$rebuild_app" ]; then
196+
REBUILD_THIS_APP=true
197+
break
198+
fi
199+
done
200+
201+
if [ "$REBUILD_THIS_APP" == "true" ]; then
202+
echo "🔨 rebuild requested"
203+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$CACHE_KEY\` | 🔨 Rebuild requested |" >> "$GITHUB_STEP_SUMMARY"
204+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
205+
--arg app "$APP_NAME" --arg sha "$CURRENT_SHA" \
206+
--arg archive_name "${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
207+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
208+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
209+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
210+
continue
211+
fi
212+
213+
# Check JFrog first before GitHub cache (available for all branches)
214+
if [ "$JFROG_AVAILABLE" == "true" ]; then
215+
JFROG_PATH="${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz"
216+
FOUND_IN_JFROG="false"
217+
218+
echo ""
219+
echo " 🔍 Checking JFrog for $APP_NAME..."
220+
echo " Path: $JFROG_PATH"
221+
echo " SHA: $SHORT_SHA"
222+
223+
# Check if artifact exists in JFrog with verbose output
224+
echo " Running: jf rt s \"$JFROG_PATH\""
225+
if SEARCH_OUTPUT=$(jf rt s "$JFROG_PATH" 2>&1); then
226+
echo " Search exit code: 0"
227+
echo " Search output:"
228+
echo "$SEARCH_OUTPUT" | sed 's/^/ /'
229+
230+
if echo "$SEARCH_OUTPUT" | grep -q "$JFROG_PATH"; then
231+
echo " ✓ Artifact found in JFrog!"
232+
ARCHIVE_NAME="${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz"
233+
echo "✓ in JFrog"
234+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$JFROG_PATH\` | 📦 In JFrog |" >> "$GITHUB_STEP_SUMMARY"
235+
APPS_IN_JFROG=$((APPS_IN_JFROG + 1))
236+
APPS_TO_RESTORE_COUNT=$((APPS_TO_RESTORE_COUNT + 1))
237+
# Add to restore list with JFrog source
238+
APPS_TO_RESTORE=$(echo "$APPS_TO_RESTORE" | jq -c --argjson app "$app_json" --arg sha "$CURRENT_SHA" --arg jfrog_path "$JFROG_PATH" --arg archive_name "$ARCHIVE_NAME" --arg source "jfrog" '. + [($app + {sha: $sha, jfrog_path: $jfrog_path, archive_name: $archive_name, source: $source})]')
239+
FOUND_IN_JFROG="true"
240+
else
241+
echo " ✗ Artifact not found in search results"
242+
fi
243+
else
244+
echo " Search exit code: non-zero"
245+
echo " ✗ Search failed with error:"
246+
echo "$SEARCH_OUTPUT" | sed 's/^/ /'
247+
fi
248+
249+
if [ "$FOUND_IN_JFROG" == "true" ]; then
250+
continue
251+
fi
252+
253+
echo "⚡ needs build (JFrog miss)"
254+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$JFROG_PATH\` | 🔨 Needs build (not in JFrog) |" >> "$GITHUB_STEP_SUMMARY"
255+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
256+
--arg app "$APP_NAME" --arg sha "$CURRENT_SHA" \
257+
--arg archive_name "${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
258+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
259+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
260+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
261+
continue
262+
fi
263+
264+
# Check if cache exists using GitHub CLI
265+
# Include --ref to access caches from the current ref (branch, PR, etc.)
266+
if ! CACHE_LIST=$(gh cache list --ref "$GITHUB_REF" --key "$CACHE_KEY" --json key --jq ".[].key" 2>&1); then
267+
echo "⚠️ Warning: Failed to query cache for $APP_NAME: $CACHE_LIST"
268+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$CACHE_KEY\` | ⚠️ Cache check failed - will build |" >> "$GITHUB_STEP_SUMMARY"
269+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
270+
--arg app "$APP_NAME" --arg sha "$CURRENT_SHA" \
271+
--arg archive_name "${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
272+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
273+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
274+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
275+
continue
276+
fi
277+
if echo "$CACHE_LIST" | grep -q "^${CACHE_KEY}$"; then
278+
APPS_CACHED=$((APPS_CACHED + 1))
279+
APPS_TO_RESTORE_COUNT=$((APPS_TO_RESTORE_COUNT + 1))
280+
echo "✓ cached"
281+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$CACHE_KEY\` | ✅ Cached |" >> "$GITHUB_STEP_SUMMARY"
282+
# Add to restore list with GitHub cache source
283+
APPS_TO_RESTORE=$(echo "$APPS_TO_RESTORE" | jq -c --argjson app "$app_json" --arg sha "$CURRENT_SHA" --arg cache_key "$CACHE_KEY" --arg source "github-cache" '. + [($app + {sha: $sha, cache_key: $cache_key, source: $source})]')
284+
else
285+
echo "⚡ needs build"
286+
echo "| $APP_NAME | \`$SHORT_SHA\` | \`$CACHE_KEY\` | 🔨 Needs build |" >> "$GITHUB_STEP_SUMMARY"
287+
APPS_TO_BUILD=$(echo "$APPS_TO_BUILD" | jq -c \
288+
--arg app "$APP_NAME" --arg sha "$CURRENT_SHA" \
289+
--arg archive_name "${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
290+
--arg jfrog_path "${ARTIFACTORY_REPOSITORY_SNAPSHOT}/apps/${CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${ARCHIVE_SUFFIX}.tar.gz" \
291+
'. + [{name: $app, sha: $sha, archive_name: $archive_name, jfrog_path: $jfrog_path}]')
292+
APPS_TO_BUILD_COUNT=$((APPS_TO_BUILD_COUNT + 1))
293+
fi
294+
295+
done < <(echo "$MATRIX" | jq -c '.[]')
296+
297+
echo "" >> "$GITHUB_STEP_SUMMARY"
298+
echo "**Summary:**" >> "$GITHUB_STEP_SUMMARY"
299+
echo "- Total apps checked: $APPS_CHECKED" >> "$GITHUB_STEP_SUMMARY"
300+
echo "- 📦 Apps in JFrog: $APPS_IN_JFROG" >> "$GITHUB_STEP_SUMMARY"
301+
echo "- ✅ Apps with cached builds: $APPS_CACHED" >> "$GITHUB_STEP_SUMMARY"
302+
echo "- 🔨 Apps needing build: $APPS_TO_BUILD_COUNT" >> "$GITHUB_STEP_SUMMARY"
303+
echo "" >> "$GITHUB_STEP_SUMMARY"
304+
305+
TOTAL_AVAILABLE=$((APPS_IN_JFROG + APPS_CACHED))
306+
if [ $TOTAL_AVAILABLE -gt 0 ] && [ $APPS_CHECKED -gt 0 ]; then
307+
CACHE_HIT_PERCENT=$((TOTAL_AVAILABLE * 100 / APPS_CHECKED))
308+
echo "**Cache hit rate: ${CACHE_HIT_PERCENT}%** 🎯" >> "$GITHUB_STEP_SUMMARY"
309+
echo "" >> "$GITHUB_STEP_SUMMARY"
310+
fi
311+
312+
echo ""
313+
echo "Summary:"
314+
echo " Total apps: $APPS_CHECKED"
315+
echo " In JFrog: $APPS_IN_JFROG"
316+
echo " Cached: $APPS_CACHED"
317+
echo " To build: $APPS_TO_BUILD_COUNT"
318+
319+
# Validate no duplicate apps in build and restore lists
320+
BUILD_APPS=$(echo "$APPS_TO_BUILD" | jq -r '.[].name' | sort)
321+
RESTORE_APPS=$(echo "$APPS_TO_RESTORE" | jq -r '.[].name' | sort)
322+
DUPLICATE_APPS=$(comm -12 <(echo "$BUILD_APPS") <(echo "$RESTORE_APPS"))
323+
324+
if [ -n "$DUPLICATE_APPS" ]; then
325+
echo "ERROR: Apps appear in both build and restore lists:"
326+
echo "$DUPLICATE_APPS"
327+
exit 1
328+
fi
329+
330+
# Validate that we built valid JSON
331+
if ! echo "$APPS_TO_BUILD" | jq empty 2>/dev/null; then
332+
echo "ERROR: Failed to build valid JSON for apps_to_build"
333+
echo "Content: $APPS_TO_BUILD"
334+
exit 1
335+
fi
336+
337+
if ! echo "$APPS_TO_RESTORE" | jq empty 2>/dev/null; then
338+
echo "ERROR: Failed to build valid JSON for apps_to_restore"
339+
echo "Content: $APPS_TO_RESTORE"
340+
exit 1
341+
fi
342+
343+
# Output app list with SHAs for the build job to use
344+
# Use proper multiline output format for GitHub Actions
345+
echo "apps_to_build<<APPS_TO_BUILD_JSON_EOF" >> "$GITHUB_OUTPUT"
346+
echo "$APPS_TO_BUILD" >> "$GITHUB_OUTPUT"
347+
echo "APPS_TO_BUILD_JSON_EOF" >> "$GITHUB_OUTPUT"
348+
349+
# Output the unified list of apps to restore (from either GitHub cache or JFrog)
350+
echo "apps_to_restore<<APPS_TO_RESTORE_JSON_EOF" >> "$GITHUB_OUTPUT"
351+
echo "$APPS_TO_RESTORE" >> "$GITHUB_OUTPUT"
352+
echo "APPS_TO_RESTORE_JSON_EOF" >> "$GITHUB_OUTPUT"
353+
354+
# Output the SHA map for all apps
355+
echo "apps_sha_map<<APPS_SHA_MAP_JSON_EOF" >> "$GITHUB_OUTPUT"
356+
echo "$APPS_SHA_MAP" >> "$GITHUB_OUTPUT"
357+
echo "APPS_SHA_MAP_JSON_EOF" >> "$GITHUB_OUTPUT"
358+
359+
# Output flags for conditional job execution
360+
if [ $APPS_TO_BUILD_COUNT -gt 0 ]; then
361+
echo "has_apps_to_build=true" >> "$GITHUB_OUTPUT"
362+
else
363+
echo "has_apps_to_build=false" >> "$GITHUB_OUTPUT"
364+
fi
365+
366+
if [ $APPS_TO_RESTORE_COUNT -gt 0 ]; then
367+
echo "has_apps_to_restore=true" >> "$GITHUB_OUTPUT"
368+
else
369+
echo "has_apps_to_restore=false" >> "$GITHUB_OUTPUT"
370+
fi
371+
372+
echo ""
373+
if [ $APPS_TO_BUILD_COUNT -eq 0 ]; then
374+
echo "🎉 All apps are cached! No builds needed."
375+
else
376+
echo "✓ Will build $APPS_TO_BUILD_COUNT app(s)"
377+
fi

0 commit comments

Comments
 (0)