Skip to content

debug pipeline push #792

debug pipeline push

debug pipeline push #792

name: Build Nextcloud Workspace artifact (Optimized)
# SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
# SPDX-FileCopyrightText: 2025 STRATO AG
# SPDX-License-Identifier: AGPL-3.0-or-later
# Optimized build workflow using GitHub Actions cache
# - Checks GitHub Actions cache for each app's current SHA
# - Only builds apps without cached artifacts
# - Significantly reduces build time by reusing cached builds via GitHub Actions cache
on:
pull_request:
paths:
- '.github/workflows/**'
- 'src/**'
- 'apps/**'
- 'apps/**/appinfo/info.xml'
- 'apps-external/**'
- 'IONOS'
- 'package.json'
- 'package-lock.json'
- 'themes/**'
- 'lib/**'
- 'tsconfig.json'
- '**.js'
- '**.ts'
- '**.vue'
- '.gitmodules'
push:
branches:
- mk/dev/ionos-dev
- ionos-stable
workflow_dispatch: # Manual trigger to bypass all caches
inputs:
force_rebuild:
description: 'Force rebuild all apps and dependencies (bypass ALL caches)'
required: false
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/mk/dev/ionos-dev' && github.run_id || github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
TARGET_PACKAGE_NAME: nc-workspace.zip
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
ARTIFACTORY_REPOSITORY_SNAPSHOT: ionos-productivity-ncwserver-snapshot
# Cache version - increment this to invalidate all caches when build process changes
# Update when: Node.js version changes, PHP version changes, build scripts modified, etc.
# Format: v<major>.<minor> (e.g., v1.0, v1.1, v2.0)
CACHE_VERSION: v1.0
permissions:
contents: read
jobs:
prepare-matrix:
runs-on: ubuntu-latest
outputs:
apps_to_build: ${{ steps.detect.outputs.apps_to_build }}
apps_to_restore: ${{ steps.detect.outputs.apps_to_restore }}
external_apps_matrix: ${{ steps.set_matrix.outputs.matrix }}
apps_sha_map: ${{ steps.detect.outputs.apps_sha_map }}
has_apps_to_build: ${{ steps.detect.outputs.has_apps_to_build }}
has_apps_to_restore: ${{ steps.detect.outputs.has_apps_to_restore }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
submodules: true
fetch-depth: 1 # Shallow clone - only need current submodule SHAs for cache detection
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y make jq
- name: Check configuration
run: |
echo ""
echo "### 🔧 Remote Trigger Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**DISABLE_REMOTE_TRIGGER value:** \`${{ vars.DISABLE_REMOTE_TRIGGER }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Event type:** \`${{ github.event_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔧 Remote Trigger Configuration"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "DISABLE_REMOTE_TRIGGER = '${{ vars.DISABLE_REMOTE_TRIGGER }}'"
echo "Event type = '${{ github.event_name }}'"
echo "Branch = '${{ github.ref_name }}'"
echo ""
if [ "${{ vars.DISABLE_REMOTE_TRIGGER }}" == "true" ]; then
echo "⚠️ Remote trigger is DISABLED"
echo " The 'trigger-remote-dev-workflow' job will be SKIPPED"
echo "**Status:** ⚠️ Remote trigger is **DISABLED**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The \`trigger-remote-dev-workflow\` job will be skipped." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To enable, delete the variable or set it to a value other than 'true' at:" >> $GITHUB_STEP_SUMMARY
echo "https://github.com/${{ github.repository }}/settings/variables/actions" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Remote trigger is ENABLED"
echo " Checking if trigger conditions are met..."
echo "**Status:** ✅ Remote trigger is **ENABLED**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Check if all conditions for trigger are met
WILL_TRIGGER=true
echo "**Trigger Conditions Check:**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ github.event_name }}" != "push" ]; then
echo "- ❌ Event must be 'push' (current: \`${{ github.event_name }}\`)" >> $GITHUB_STEP_SUMMARY
echo " ❌ Event type is '${{ github.event_name }}' (must be 'push')"
WILL_TRIGGER=false
else
echo "- ✅ Event is 'push'" >> $GITHUB_STEP_SUMMARY
echo " ✅ Event type is 'push'"
fi
if [ "${{ github.ref_name }}" != "mk/dev/ionos-dev" ] && [ "${{ github.ref_name }}" != "ionos-stable" ]; then
echo "- ❌ Branch must be 'mk/dev/ionos-dev' or 'ionos-stable' (current: \`${{ github.ref_name }}\`)" >> $GITHUB_STEP_SUMMARY
echo " ❌ Branch is '${{ github.ref_name }}' (must be 'mk/dev/ionos-dev' or 'ionos-stable')"
WILL_TRIGGER=false
else
echo "- ✅ Branch is '\`${{ github.ref_name }}\`'" >> $GITHUB_STEP_SUMMARY
echo " ✅ Branch is '${{ github.ref_name }}'"
fi
echo "- ℹ️ All dependent jobs must succeed (checked at job runtime)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$WILL_TRIGGER" = "true" ]; then
echo "**Expected:** The \`trigger-remote-dev-workflow\` job **WILL RUN** (if all dependent jobs succeed)." >> $GITHUB_STEP_SUMMARY
echo ""
echo "🎯 Expected: trigger-remote-dev-workflow job WILL RUN (if all dependent jobs succeed)"
else
echo "**Expected:** The \`trigger-remote-dev-workflow\` job **WILL BE SKIPPED** due to unmet conditions above." >> $GITHUB_STEP_SUMMARY
echo ""
echo "⏭️ Expected: trigger-remote-dev-workflow job WILL BE SKIPPED"
fi
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# - name: List caches before restore
# run: gh cache list
# env:
# GH_TOKEN: ${{ github.token }}
#
- name: Generate apps matrix dynamically from Makefile
id: set_matrix
run: |
echo "matrix=[]" >> $GITHUB_OUTPUT
# # Generate matrix from Makefile - single source of truth
# echo "Generating matrix from Makefile..."
# matrix_output=$(make -f IONOS/Makefile generate_external_apps_matrix_json 2>&1)
#
# # Filter out info messages to get just the JSON
# # Note: Use same filtering logic as validation script to ensure consistency
# if echo "$matrix_output" | grep -q '^\[i\]'; then
# matrix=$(echo "$matrix_output" | grep -v '^\[i\]')
# else
# matrix="$matrix_output"
# fi
#
# # Validate JSON
# if ! echo "$matrix" | jq empty 2>/dev/null; then
# echo "Error: Generated matrix is not valid JSON"
# echo "Output: $matrix_output"
# exit 1
# fi
#
# # Output as compact format
# echo "matrix=$(echo "$matrix" | jq -c '.')" >> $GITHUB_OUTPUT
# echo "Matrix generated successfully with $(echo "$matrix" | jq 'length') apps"
#
- name: Collect apps and their SHAs for cache-based building
id: detect
env:
GH_TOKEN: ${{ github.token }}
CACHE_VERSION: ${{ env.CACHE_VERSION }}
FORCE_REBUILD: ${{ github.event.inputs.force_rebuild || 'false' }}
JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }}
JF_USER: ${{ secrets.JF_ARTIFACTORY_USER }}
JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
ARTIFACTORY_REPOSITORY_SNAPSHOT: ${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}
GITHUB_REF: ${{ github.ref }}
run: |
# bash .github/scripts/detect-app-cache.sh '${{ steps.set_matrix.outputs.matrix }}'
echo "has_apps_to_build=false" >> "$GITHUB_OUTPUT"
echo "has_apps_to_restore=false" >> "$GITHUB_OUTPUT"
build-external-apps:
runs-on: ubuntu-latest
needs: prepare-matrix
# Only run if there are actually apps to build (prevents runner from starting)
if: needs.prepare-matrix.outputs.has_apps_to_build == 'true'
permissions:
contents: read
name: build-external-apps
strategy:
max-parallel: 20
# matrix:
# # Use the filtered list of apps that need building (not in cache)
# app_info: ${{ fromJson(needs.prepare-matrix.outputs.apps_to_build) }}
steps:
- name: simulate success
run: exit 0
# - name: Get app configuration from full matrix
# id: app-config
# run: |
# # Get the full matrix to look up app configuration
# FULL_MATRIX='${{ needs.prepare-matrix.outputs.external_apps_matrix }}'
# APP_NAME='${{ matrix.app_info.name }}'
#
# # Find the app configuration in the full matrix
# APP_CONFIG=$(echo "$FULL_MATRIX" | jq -c --arg name "$APP_NAME" '.[] | select(.name == $name)')
#
# if [ -z "$APP_CONFIG" ]; then
# echo "ERROR: Could not find configuration for $APP_NAME"
# exit 1
# fi
#
# # Extract configuration values
# APP_PATH=$(echo "$APP_CONFIG" | jq -r '.path')
# HAS_NPM=$(echo "$APP_CONFIG" | jq -r '.has_npm')
# HAS_COMPOSER=$(echo "$APP_CONFIG" | jq -r '.has_composer')
# MAKEFILE_TARGET=$(echo "$APP_CONFIG" | jq -r '.makefile_target')
#
# # Set outputs
# echo "path=$APP_PATH" >> $GITHUB_OUTPUT
# echo "has-npm=$HAS_NPM" >> $GITHUB_OUTPUT
# echo "has-composer=$HAS_COMPOSER" >> $GITHUB_OUTPUT
# echo "makefile-target=$MAKEFILE_TARGET" >> $GITHUB_OUTPUT
# echo "Building $APP_NAME from $APP_PATH (SHA: ${{ matrix.app_info.sha }})"
#
# - name: Checkout server
# uses: actions/checkout@v5
# with:
# submodules: true
# fetch-depth: 1
#
# - name: Set up node with version from package.json's engines
# if: steps.app-config.outputs.has-npm == 'true'
# uses: actions/setup-node@v6
# with:
# node-version-file: "package.json"
# cache: 'npm'
# cache-dependency-path: ${{ steps.app-config.outputs.path }}/package-lock.json
#
# - name: Setup PHP with PECL extension
# if: steps.app-config.outputs.has-composer == 'true'
# uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 #v2.31.1
# with:
# php-version: '8.3'
# tools: composer:v2
# extensions: gd, zip, curl, xml, xmlrpc, mbstring, sqlite, xdebug, pgsql, intl, imagick, gmp, apcu, bcmath, redis, soap, imap, opcache
# env:
# runner: ubuntu-latest
#
# - name: Cache Composer dependencies for ${{ matrix.app_info.name }}
# if: steps.app-config.outputs.has-composer == 'true' && github.event.inputs.force_rebuild != 'true'
# uses: actions/cache@v4
# with:
# path: ${{ steps.app-config.outputs.path }}/vendor
# key: ${{ runner.os }}-composer-${{ matrix.app_info.name }}-${{ hashFiles(format('{0}/composer.lock', steps.app-config.outputs.path)) }}
# restore-keys: |
# ${{ runner.os }}-composer-${{ matrix.app_info.name }}-
#
# - name: Build ${{ matrix.app_info.name }} app
# run: make -f IONOS/Makefile ${{ steps.app-config.outputs.makefile-target }}
#
# - name: Report build completion
# if: success()
# run: |
# echo "### ✅ Built ${{ matrix.app_info.name }}" >> $GITHUB_STEP_SUMMARY
# echo "- **SHA:** \`${{ matrix.app_info.sha }}\`" >> $GITHUB_STEP_SUMMARY
# echo "- **Path:** ${{ steps.app-config.outputs.path }}" >> $GITHUB_STEP_SUMMARY
# echo "- **Status:** Success" >> $GITHUB_STEP_SUMMARY
# echo "" >> $GITHUB_STEP_SUMMARY
#
# # Save built app to cache for future runs
# - name: Save build artifacts to cache
# uses: actions/cache/save@v4
# with:
# path: ${{ steps.app-config.outputs.path }}
# key: ${{ env.CACHE_VERSION }}-app-build-${{ matrix.app_info.name }}-${{ matrix.app_info.sha }}
#
# # Push to JFrog for mk/dev/ionos-dev branch builds
# - name: Setup JFrog CLI
# uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.4.1
# env:
# JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }}
# JF_USER: ${{ secrets.JF_ARTIFACTORY_USER }}
# JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
#
# - name: Ping the JF server
# run: |
# # Ping the server
# jf rt ping
#
# - name: Push ${{ matrix.app_info.name }} to JFrog
# run: |
# set -e
# APP_NAME="${{ matrix.app_info.name }}"
# APP_SHA="${{ matrix.app_info.sha }}"
# APP_PATH="${{ steps.app-config.outputs.path }}"
#
# echo "=== JFrog Upload Debug Info ==="
# echo "📦 Packaging $APP_NAME for JFrog upload..."
# echo "App Name: $APP_NAME"
# echo "App SHA: $APP_SHA"
# echo "App Path: $APP_PATH"
# echo "Repository: ${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}"
# echo "==============================="
#
# # Verify app path exists
# if [ ! -d "$APP_PATH" ]; then
# echo "❌ ERROR: App path does not exist: $APP_PATH"
# exit 1
# fi
#
# echo "App directory contents (top level):"
# ls -la "$APP_PATH" | head -20
#
# # Create tar.gz archive of the built app (excluding node_modules and other build artifacts)
# ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz"
# echo ""
# echo "Creating archive: $ARCHIVE_NAME"
# echo "Running: tar -czf \"$ARCHIVE_NAME\" --exclude=\"node_modules\" --exclude=\".git\" --exclude=\"*.log\" -C \"$(dirname "$APP_PATH")\" \"$(basename "$APP_PATH")\""
#
# tar -czf "$ARCHIVE_NAME" \
# --exclude="node_modules" \
# --exclude=".git" \
# --exclude="*.log" \
# -C "$(dirname "$APP_PATH")" \
# "$(basename "$APP_PATH")"
#
# echo "✓ Archive created successfully"
# echo "Archive size:"
# ls -lh "$ARCHIVE_NAME"
#
# # Upload to JFrog - store in snapshot repo under dev/apps/
# # Include CACHE_VERSION in path to enable complete cache invalidation
# JFROG_PATH="${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/apps/${{ env.CACHE_VERSION }}/${APP_NAME}/${ARCHIVE_NAME}"
#
# echo ""
# echo "Uploading to JFrog..."
# echo "Target Path: $JFROG_PATH"
# echo "Properties: app.name=${APP_NAME};app.sha=${APP_SHA};vcs.branch=${{ github.ref_name }};vcs.revision=${{ github.sha }}"
# echo "Running: jf rt upload \"$ARCHIVE_NAME\" \"$JFROG_PATH\" --target-props \"...\""
#
# if jf rt upload "$ARCHIVE_NAME" "$JFROG_PATH" \
# --target-props "app.name=${APP_NAME};app.sha=${APP_SHA};vcs.branch=${{ github.ref_name }};vcs.revision=${{ github.sha }}"; then
# echo "✅ Successfully uploaded $APP_NAME to JFrog"
# echo ""
# echo "Verifying upload..."
# if jf rt s "$JFROG_PATH"; then
# echo "✓ Upload verified - artifact is accessible in JFrog"
# else
# echo "⚠ Upload succeeded but verification search failed"
# fi
# else
# UPLOAD_EXIT_CODE=$?
# echo "❌ Failed to upload to JFrog (exit code: $UPLOAD_EXIT_CODE)"
# echo "⚠️ Continuing workflow despite upload failure..."
# fi
#
# # Clean up archive
# echo ""
# echo "Cleaning up local archive..."
# rm -f "$ARCHIVE_NAME"
# echo "✓ Cleanup complete"
#
# - name: Upload ${{ matrix.app_info.name }} build artifacts
# uses: actions/upload-artifact@v4
# with:
# retention-days: 1
# name: external-app-build-${{ matrix.app_info.name }}
# path: |
# ${{ steps.app-config.outputs.path }}
# !${{ steps.app-config.outputs.path }}/node_modules
build-artifact:
runs-on: ubuntu-latest
needs: [prepare-matrix, build-external-apps]
# Always run this job, even if build-external-apps is skipped
if: |
always() &&
needs.prepare-matrix.result == 'success' &&
(needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped')
permissions:
contents: read
outputs:
NC_VERSION: ${{ steps.get_nc_version.outputs.NC_VERSION }}
name: build-artifact
steps:
- name: Checkout server
uses: actions/checkout@v5
with:
submodules: true
fetch-depth: 1
- name: simulate success
run: exit 0
# - name: Setup JFrog CLI
# if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true'
# uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.4.1
# env:
# JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }}
# JF_USER: ${{ secrets.JF_ARTIFACTORY_USER }}
# JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
#
# - name: Ping the JF server
# run: |
# # Ping the server
# jf rt ping
#
# - name: Restore cached apps
# if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true'
# run: |
# set -e
#
# echo "📦 Restoring cached apps..."
# APPS_TO_RESTORE='${{ needs.prepare-matrix.outputs.apps_to_restore }}'
#
# # Process each app in the restore list
# echo "$APPS_TO_RESTORE" | jq -c '.[]' | while read -r app_json; do
# APP_NAME=$(echo "$app_json" | jq -r '.name')
# APP_SHA=$(echo "$app_json" | jq -r '.sha')
# APP_PATH=$(echo "$app_json" | jq -r '.path')
# SOURCE=$(echo "$app_json" | jq -r '.source')
#
# echo ""
# echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# echo "Restoring: $APP_NAME (source: $SOURCE)"
# echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
#
# if [ "$SOURCE" == "jfrog" ]; then
# # Restore from JFrog
# JFROG_PATH=$(echo "$app_json" | jq -r '.jfrog_path')
# ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz"
#
# echo "📥 Downloading from JFrog: $JFROG_PATH"
#
# if jf rt download "$JFROG_PATH" "$ARCHIVE_NAME" --flat=true; then
# echo "✅ Downloaded successfully"
# echo "Extracting to $APP_PATH..."
# mkdir -p "$(dirname "$APP_PATH")"
# tar -xzf "$ARCHIVE_NAME" -C "$(dirname "$APP_PATH")"
#
# if [ -d "$APP_PATH" ] && [ -f "$APP_PATH/appinfo/info.xml" ]; then
# echo "✅ Restored $APP_NAME from JFrog"
# else
# echo "❌ Failed to extract or validate $APP_NAME"
# exit 1
# fi
#
# rm -f "$ARCHIVE_NAME"
# else
# echo "❌ Failed to download from JFrog"
# exit 1
# fi
#
# elif [ "$SOURCE" == "github-cache" ]; then
# # Restore from GitHub cache
# CACHE_KEY=$(echo "$app_json" | jq -r '.cache_key')
#
# echo "💾 Restoring from GitHub cache: $CACHE_KEY"
#
# # Use actions/cache/restore in a way that works in a script context
# # We need to use gh CLI to restore the cache
# if gh cache restore "$CACHE_KEY" --key "$CACHE_KEY"; then
# echo "✅ Restored $APP_NAME from GitHub cache"
#
# # Validate restoration
# if [ ! -d "$APP_PATH" ] || [ ! -f "$APP_PATH/appinfo/info.xml" ]; then
# echo "❌ Validation failed for $APP_NAME"
# exit 1
# fi
# else
# echo "❌ Failed to restore from GitHub cache"
# exit 1
# fi
# else
# echo "❌ Unknown source: $SOURCE"
# exit 1
# fi
# done
#
# echo ""
# echo "✅ All cached apps restored successfully"
# env:
# GH_TOKEN: ${{ github.token }}
#
# - name: Download build external apps
# uses: actions/download-artifact@v5
# with:
# pattern: external-app-build-*
# path: apps-external/
#
# - name: Reorganize downloaded apps-external artifacts
# run: |
# cd apps-external/
#
# echo "Initial structure:"
# ls -la
#
# # Move contents from external-app-build-* directories to their target directories
# for artifact_dir in external-app-build-*; do
# if [ -d "$artifact_dir" ]; then
# # Extract app name from artifact directory name
# app_name=${artifact_dir#external-app-build-}
#
# echo "Processing artifact: $artifact_dir -> $app_name"
#
# # If target directory exists, merge the contents from the artifact directory containing build artifacts
# if [ -d "$app_name" ]; then
# echo "Target directory $app_name exists, merging contents from $artifact_dir"
# # Copy contents from artifact directory to target directory
# cp -r "$artifact_dir"/* "$app_name"/
# # Remove the now-empty artifact directory
# rm -rf "$artifact_dir"
# else
# # Move the artifact directory to the proper app name
# echo "Moving $artifact_dir to $app_name"
# mv "$artifact_dir" "$app_name"
# fi
# fi
# done
#
# echo "Reorganization complete. Final structure:"
# ls -la
#
# - name: Verify downloaded artifacts structure
# run: |
# echo "External apps structure:"
# ls -la apps-external/
# for app_dir in apps-external/*/; do
# if [ -d "$app_dir" ]; then
# echo "Contents of $app_dir:"
# ls -la "$app_dir"
# fi
# done
#
# - name: Set up node with version from package.json's engines
# uses: actions/setup-node@v6
# with:
# node-version-file: "package.json"
# cache: ${{ github.event.inputs.force_rebuild != 'true' && 'npm' || '' }}
#
# - name: Install Dependencies
# run: sudo apt-get update && sudo apt-get install -y make zip unzip
#
# - name: Print dependencies versions
# run: make --version && node --version && npm --version
#
# - name: Setup PHP with PECL extension
# uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 #v2.31.1
# with:
# php-version: '8.3'
# tools: composer:v2
# extensions: gd, zip, curl, xml, xmlrpc, mbstring, sqlite, xdebug, pgsql, intl, imagick, gmp, apcu, bcmath, redis, soap, imap, opcache
# env:
# runner: ubuntu-latest
#
# - name: Cache Composer dependencies
# if: github.event.inputs.force_rebuild != 'true'
# uses: actions/cache@v4
# with:
# path: vendor
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
# restore-keys: |
# ${{ runner.os }}-composer-
#
# - name: Print PHP install
# run: php -i && php -m
#
# - name: Build Nextcloud
# run: make -f IONOS/Makefile build_ncw
#
# - name: Add config partials
# run: make -f IONOS/Makefile add_config_partials
#
# - name: Zip dependencies
# run: make -f IONOS/Makefile zip_dependencies TARGET_PACKAGE_NAME=${{ env.TARGET_PACKAGE_NAME }}
#
# - name: Get NC version
# id: get_nc_version
# continue-on-error: false
# run: |
# NC_VERSION=$(jq -r '.ncVersion' version.json)
# echo "NC_VERSION: $NC_VERSION"
#
# if [ -z "$NC_VERSION" ]; then
# echo "NC_VERSION is empty"
# exit 1
# fi
#
# echo "NC_VERSION=$NC_VERSION" >> $GITHUB_OUTPUT
#
# - name: Upload artifact result for job build-artifact
# uses: actions/upload-artifact@v4
# with:
# retention-days: 30
# name: nextcloud_workspace_build_artifact
# path: ${{ env.TARGET_PACKAGE_NAME }}
- name: Show changes on failure
if: failure()
run: |
git status
git --no-pager diff
exit 1 # make it red to grab attention
upload-to-artifactory:
runs-on: self-hosted
# Upload the artifact to the Artifactory repository on PR *OR* on "mk/dev/ionos-dev|ionos-stable" branch push defined in the on:push:branches
if: |
always() &&
(github.event_name == 'pull_request' || github.ref_name == 'mk/dev/ionos-dev' || github.ref_name == 'ionos-stable') &&
needs.prepare-matrix.result == 'success' &&
(needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped') &&
needs.build-artifact.result == 'success'
name: Push to artifactory
needs: [prepare-matrix, build-external-apps, build-artifact]
outputs:
ARTIFACTORY_LAST_BUILD_PATH: ${{ steps.artifactory_upload.outputs.ARTIFACTORY_LAST_BUILD_PATH }}
env:
BUILD_NAME: "nextcloud-workspace-snapshot"
steps:
- name: simulate success
run: exit 0
# - name: Check prerequisites
# run: |
# # count the number of secrets that are set
# echo "Checking if required secrets are set..."
# error_count=0
#
# if [ -z "${{ secrets.JF_ARTIFACTORY_URL }}" ]; then
# # output error to github actions log
# echo "::error::JF_ARTIFACTORY_URL secret is not set"
# error_count=$((error_count + 1))
# fi
#
# if [ -z "${{ secrets.JF_ARTIFACTORY_USER }}" ]; then
# echo "::error::JF_ARTIFACTORY_USER secret is not set"
# error_count=$((error_count + 1))
# fi
#
# if [ -z "${{ secrets.JF_ACCESS_TOKEN }}" ]; then
# echo "::error::JF_ACCESS_TOKEN secret is not set"
# error_count=$((error_count + 1))
# fi
#
# # abort if any of the required secrets are not set
# if [ $error_count -ne 0 ]; then
# echo "::error::Required secrets are not set. Aborting."
# exit 1
# fi
#
# - name: Download artifact zip
# uses: actions/download-artifact@v5
# with:
# name: nextcloud_workspace_build_artifact
#
# # This action sets up the JFrog CLI with the Artifactory URL and access token
# - uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.4.1
# env:
# JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }}
# JF_USER: ${{ secrets.JF_ARTIFACTORY_USER }}
# JF_ACCESS_TOKEN: ${{ secrets.JF_ACCESS_TOKEN }}
#
# - name: Ping the JF server
# run: |
# # Ping the server
# jf rt ping
#
# - name: Upload build to artifactory
# id: artifactory_upload
# run: |
# # PR builds are stored in a separate directory as "dev/pr/nextcloud-workspace-pr-<number>.zip"
# # Push to "mk/dev/ionos-dev" branch is stored as "dev/nextcloud-workspace-<ncVersion>.zip"
#
# ARTIFACTORY_STAGE_PREFIX="dev"
#
# # set ARTIFACTORY_STAGE_PREFIX=stable on ionos-stable branch
# if [ "${{ github.ref_name }}" == "ionos-stable" ]; then
# ARTIFACTORY_STAGE_PREFIX="stable"
# fi
#
# export PATH_TO_DIRECTORY="${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/${ARTIFACTORY_STAGE_PREFIX}"
# PATH_TO_FILE="pr/nextcloud-workspace-pr-${{ github.event.pull_request.number }}.zip"
#
# if [ -z "${{ github.event.pull_request.number }}" ]; then
# PATH_TO_FILE="nextcloud-workspace-${{ needs.build-artifact.outputs.NC_VERSION }}.zip"
# fi
#
# export PATH_TO_LATEST_ARTIFACT="${PATH_TO_DIRECTORY}/${PATH_TO_FILE}"
#
# # Upload with retry logic (3 attempts with 30s delay)
# MAX_ATTEMPTS=3
# ATTEMPT=1
# UPLOAD_SUCCESS=false
# DELAY_SEC=10
#
# while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
# echo "Upload attempt $ATTEMPT of $MAX_ATTEMPTS..."
#
# if jf rt upload "${{ env.TARGET_PACKAGE_NAME }}" \
# --build-name "${{ env.BUILD_NAME }}" \
# --build-number ${{ github.run_number }} \
# --target-props "build.nc_version=${{ needs.build-artifact.outputs.NC_VERSION }};vcs.branch=${{ github.ref }};vcs.revision=${{ github.sha }}" \
# $PATH_TO_LATEST_ARTIFACT; then
# UPLOAD_SUCCESS=true
# echo "✅ Upload successful on attempt $ATTEMPT"
# break
# else
# echo "⚠️ Upload attempt $ATTEMPT failed"
# if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
# echo "Waiting $DELAY_SEC seconds before retry..."
# sleep $DELAY_SEC
# DELAY_SEC=$((DELAY_SEC * 2)) # Exponential backoff: delays are 10s, then 20s (sleep occurs after failed attempts)
# fi
# fi
#
# ATTEMPT=$((ATTEMPT + 1))
# done
#
# if [ "$UPLOAD_SUCCESS" != "true" ]; then
# echo "❌ Upload failed after $MAX_ATTEMPTS attempts"
# exit 1
# fi
#
# echo "ARTIFACTORY_LAST_BUILD_PATH=${PATH_TO_LATEST_ARTIFACT}" >> $GITHUB_OUTPUT
- name: Show changes on failure
if: failure()
run: |
git status
git --no-pager diff
exit 1 # make it red to grab attention
nextcloud-workspace-artifact-to-ghcr_io:
runs-on: ubuntu-latest
# Only run if build-artifact succeeded
if: |
always() &&
needs.prepare-matrix.result == 'success' &&
(needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped') &&
needs.build-artifact.result == 'success'
permissions:
contents: read
packages: write
name: Push artifact to ghcr.io
needs: [prepare-matrix, build-external-apps, build-artifact]
steps:
- name: simulate success
run: exit 0
# - name: Download artifact zip
# uses: actions/download-artifact@v5
# with:
# name: nextcloud_workspace_build_artifact
#
# - name: Log in to the Container registry
# uses: docker/login-action@v3
# with:
# registry: ${{ env.REGISTRY }}
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
#
# - name: Extract metadata (tags, labels) for Docker
# id: meta
# uses: docker/metadata-action@v5
# with:
# images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
#
# - name: Create Dockerfile
# run: |
# cat >Dockerfile << EOF
# FROM busybox as builder
# COPY ./${{ env.TARGET_PACKAGE_NAME }} /
# WORKDIR /builder
# RUN unzip /${{ env.TARGET_PACKAGE_NAME }} -d /builder
#
# FROM scratch
# WORKDIR /app
# VOLUME /app
# COPY --from=builder /builder /app
# EOF
#
# - name: Build and push Docker image
# uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
# with:
# context: .
# push: true
# tags: ${{ steps.meta.outputs.tags }}
# labels: ${{ steps.meta.outputs.labels }}
- name: Show changes on failure
if: failure()
run: |
echo "Git status:"
git status
echo "Git diff:"
git diff
exit 1 # make it red to grab attention
trigger-remote-dev-workflow:
runs-on: self-hosted
name: Trigger remote workflow
needs: [prepare-matrix, build-external-apps, build-artifact, upload-to-artifactory]
# Trigger remote build on "mk/dev/ionos-dev|ionos-stable" branch *push* defined in the on:push:branches
# Can be disabled via repository variable 'DISABLE_REMOTE_TRIGGER' (set to 'true' to disable)
# Configure at: https://github.com/IONOS-Productivity/ncw-server/settings/variables/actions
if: |
github.event_name == 'push' &&
(github.ref_name == 'mk/dev/ionos-dev' || github.ref_name == 'ionos-stable') &&
needs.prepare-matrix.result == 'success' &&
(needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped') &&
needs.build-artifact.result == 'success' &&
needs.upload-to-artifactory.result == 'success' &&
vars.DISABLE_REMOTE_TRIGGER != 'true'
steps:
- name: Trigger remote workflow
run: |
# Enable command echo for debugging purposes
set -x
# Determine build type based on branch:
# - 'mk/dev/ionos-dev' branch triggers 'dev' build type
# - 'ionos-stable' branch triggers 'stable' build type
BUILD_TYPE="dev"
# Override build type for stable branch
if [ "${{ github.ref_name }}" == "ionos-stable" ]; then
BUILD_TYPE="stable"
fi
# Trigger GitLab pipeline via webhook with retry logic (3 attempts with 30s delay)
MAX_ATTEMPTS=3
ATTEMPT=1
TRIGGER_SUCCESS=false
DELAY_SEC=5
# while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
# echo "Trigger attempt $ATTEMPT of $MAX_ATTEMPTS..."
#
# if curl \
# --silent \
# --insecure \
# --request POST \
# --fail-with-body \
# -o response.json \
# --form token=${{ secrets.GITLAB_TOKEN }} \
# --form ref="stable" \
# --form "variables[GITHUB_SHA]=${{ github.sha }}" \
# --form "variables[ARTIFACTORY_LAST_BUILD_PATH]=${{ needs.upload-to-artifactory.outputs.ARTIFACTORY_LAST_BUILD_PATH }}" \
# --form "variables[NC_VERSION]=${{ needs.build-artifact.outputs.NC_VERSION }}" \
# --form "variables[BUILD_ID]=${{ github.run_id }}" \
# --form "variables[BUILD_TYPE]=${BUILD_TYPE}" \
# "${{ secrets.GITLAB_TRIGGER_URL }}"; then
# TRIGGER_SUCCESS=true
# echo "✅ Trigger successful on attempt $ATTEMPT"
# break
# else
# RETCODE="$?"
# echo "⚠️ Trigger attempt $ATTEMPT failed with code $RETCODE"
# if [ -f response.json ]; then
# jq . response.json || cat response.json
# fi
# if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
# echo "Waiting ${DELAY_SEC} seconds before retry..."
# sleep $DELAY_SEC
# DELAY_SEC=$((DELAY_SEC * 2)) # Exponential backoff: 5s, 10s, 20s
# fi
# fi
#
# ATTEMPT=$((ATTEMPT + 1))
# done
#
# if [ "$TRIGGER_SUCCESS" != "true" ]; then
# echo "❌ Trigger failed after $MAX_ATTEMPTS attempts"
# if [ -f response.json ]; then
# jq . response.json || cat response.json
# fi
# exit 1
# fi
#
# # Disable command echo
# set +x
#
# # Print and parse json
# # jq . response.json
# echo "json<<END" >> $GITHUB_OUTPUT
# cat response.json >> $GITHUB_OUTPUT
# echo "END" >> $GITHUB_OUTPUT
# echo "web_url<<END" >> $GITHUB_OUTPUT
# cat response.json | jq --raw-output '.web_url' >> $GITHUB_OUTPUT
# echo "END" >> $GITHUB_OUTPUT
- name: Show changes on failure
if: failure()
run: |
git status
git --no-pager diff
exit 1 # make it red to grab attention
debug-pipeline-status:
runs-on: ubuntu-latest
name: Debug Pipeline Status
needs: [prepare-matrix, build-external-apps, build-artifact, upload-to-artifactory, nextcloud-workspace-artifact-to-ghcr_io, trigger-remote-dev-workflow]
if: always() # Always run this job regardless of previous job status
steps:
- name: Collect and display pipeline status
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔍 Pipeline Run Status Analysis"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Workflow metadata
echo "### 📋 Workflow Metadata"
echo "**Workflow:** ${{ github.workflow }}"
echo "**Run ID:** ${{ github.run_id }}"
echo "**Run Number:** ${{ github.run_number }}"
echo "**Run Attempt:** ${{ github.run_attempt }}"
echo "**Event:** ${{ github.event_name }}"
echo "**Branch/Ref:** ${{ github.ref_name }}"
echo "**Commit SHA:** ${{ github.sha }}"
echo "**Actor:** ${{ github.actor }}"
echo "**Triggered by:** ${{ github.triggering_actor }}"
echo ""
# Job status summary
echo "### 🎯 Job Status Summary"
echo ""
echo "| Job Name | Status | Conclusion |"
echo "|----------|--------|------------|"
echo "| prepare-matrix | ${{ needs.prepare-matrix.result }} | - |"
echo "| build-external-apps | ${{ needs.build-external-apps.result }} | - |"
echo "| build-artifact | ${{ needs.build-artifact.result }} | - |"
echo "| upload-to-artifactory | ${{ needs.upload-to-artifactory.result }} | - |"
echo "| nextcloud-workspace-artifact-to-ghcr_io | ${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }} | - |"
echo "| trigger-remote-dev-workflow | ${{ needs.trigger-remote-dev-workflow.result }} | - |"
echo ""
# Detailed job analysis
echo "### 📊 Detailed Job Analysis"
echo ""
# Function to analyze job result
analyze_job() {
local job_name=$1
local job_result=$2
case $job_result in
"success")
echo "✅ **$job_name**: Completed successfully"
;;
"failure")
echo "❌ **$job_name**: Failed"
;;
"cancelled")
echo "🚫 **$job_name**: Cancelled"
;;
"skipped")
echo "⏭️ **$job_name**: Skipped"
;;
*)
echo "❓ **$job_name**: Unknown status ($job_result)"
;;
esac
}
analyze_job "prepare-matrix" "${{ needs.prepare-matrix.result }}"
analyze_job "build-external-apps" "${{ needs.build-external-apps.result }}"
analyze_job "build-artifact" "${{ needs.build-artifact.result }}"
analyze_job "upload-to-artifactory" "${{ needs.upload-to-artifactory.result }}"
analyze_job "nextcloud-workspace-artifact-to-ghcr_io" "${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }}"
analyze_job "trigger-remote-dev-workflow" "${{ needs.trigger-remote-dev-workflow.result }}"
echo ""
# Overall pipeline status
echo "### 🎭 Overall Pipeline Status"
echo ""
FAILED_JOBS=""
SKIPPED_JOBS=""
SUCCESS_JOBS=""
if [ "${{ needs.prepare-matrix.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS prepare-matrix"; fi
if [ "${{ needs.build-external-apps.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS build-external-apps"; fi
if [ "${{ needs.build-artifact.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS build-artifact"; fi
if [ "${{ needs.upload-to-artifactory.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS upload-to-artifactory"; fi
if [ "${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS nextcloud-workspace-artifact-to-ghcr_io"; fi
if [ "${{ needs.trigger-remote-dev-workflow.result }}" == "failure" ]; then FAILED_JOBS="$FAILED_JOBS trigger-remote-dev-workflow"; fi
if [ "${{ needs.build-external-apps.result }}" == "skipped" ]; then SKIPPED_JOBS="$SKIPPED_JOBS build-external-apps"; fi
if [ "${{ needs.upload-to-artifactory.result }}" == "skipped" ]; then SKIPPED_JOBS="$SKIPPED_JOBS upload-to-artifactory"; fi
if [ "${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }}" == "skipped" ]; then SKIPPED_JOBS="$SKIPPED_JOBS nextcloud-workspace-artifact-to-ghcr_io"; fi
if [ "${{ needs.trigger-remote-dev-workflow.result }}" == "skipped" ]; then SKIPPED_JOBS="$SKIPPED_JOBS trigger-remote-dev-workflow"; fi
if [ "${{ needs.prepare-matrix.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS prepare-matrix"; fi
if [ "${{ needs.build-external-apps.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS build-external-apps"; fi
if [ "${{ needs.build-artifact.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS build-artifact"; fi
if [ "${{ needs.upload-to-artifactory.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS upload-to-artifactory"; fi
if [ "${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS nextcloud-workspace-artifact-to-ghcr_io"; fi
if [ "${{ needs.trigger-remote-dev-workflow.result }}" == "success" ]; then SUCCESS_JOBS="$SUCCESS_JOBS trigger-remote-dev-workflow"; fi
if [ -n "$FAILED_JOBS" ]; then
echo "❌ **Pipeline Status:** FAILED"
echo ""
echo "**Failed Jobs:**"
for job in $FAILED_JOBS; do
echo " - $job"
done
elif [ "${{ needs.prepare-matrix.result }}" == "success" ] && [ "${{ needs.build-artifact.result }}" == "success" ]; then
echo "✅ **Pipeline Status:** SUCCESS (core jobs completed)"
else
echo "⚠️ **Pipeline Status:** PARTIAL (some jobs incomplete)"
fi
if [ -n "$SKIPPED_JOBS" ]; then
echo ""
echo "**Skipped Jobs:**"
for job in $SKIPPED_JOBS; do
echo " - $job"
done
fi
if [ -n "$SUCCESS_JOBS" ]; then
echo ""
echo "**Successful Jobs:**"
for job in $SUCCESS_JOBS; do
echo " - $job"
done
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Add to GitHub step summary
{
echo "# 🔍 Pipeline Run Status Analysis"
echo ""
echo "## 📋 Workflow Metadata"
echo ""
echo "- **Workflow:** ${{ github.workflow }}"
echo "- **Run ID:** [\`${{ github.run_id }}\`](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
echo "- **Run Number:** ${{ github.run_number }}"
echo "- **Run Attempt:** ${{ github.run_attempt }}"
echo "- **Event:** ${{ github.event_name }}"
echo "- **Branch/Ref:** ${{ github.ref_name }}"
echo "- **Commit:** [\`${{ github.sha }}\`](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})"
echo "- **Actor:** @${{ github.actor }}"
echo "- **Triggered by:** @${{ github.triggering_actor }}"
echo ""
echo "## 🎯 Job Status Summary"
echo ""
echo "| Job Name | Status |"
echo "|----------|--------|"
echo "| prepare-matrix | ${{ needs.prepare-matrix.result == 'success' && '✅' || needs.prepare-matrix.result == 'failure' && '❌' || needs.prepare-matrix.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.prepare-matrix.result }} |"
echo "| build-external-apps | ${{ needs.build-external-apps.result == 'success' && '✅' || needs.build-external-apps.result == 'failure' && '❌' || needs.build-external-apps.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.build-external-apps.result }} |"
echo "| build-artifact | ${{ needs.build-artifact.result == 'success' && '✅' || needs.build-artifact.result == 'failure' && '❌' || needs.build-artifact.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.build-artifact.result }} |"
echo "| upload-to-artifactory | ${{ needs.upload-to-artifactory.result == 'success' && '✅' || needs.upload-to-artifactory.result == 'failure' && '❌' || needs.upload-to-artifactory.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.upload-to-artifactory.result }} |"
echo "| nextcloud-workspace-artifact-to-ghcr_io | ${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result == 'success' && '✅' || needs.nextcloud-workspace-artifact-to-ghcr_io.result == 'failure' && '❌' || needs.nextcloud-workspace-artifact-to-ghcr_io.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.nextcloud-workspace-artifact-to-ghcr_io.result }} |"
echo "| trigger-remote-dev-workflow | ${{ needs.trigger-remote-dev-workflow.result == 'success' && '✅' || needs.trigger-remote-dev-workflow.result == 'failure' && '❌' || needs.trigger-remote-dev_workflow.result == 'skipped' && '⏭️' || '❓' }} ${{ needs.trigger-remote-dev-workflow.result }} |"
echo ""
if [ -n "$FAILED_JOBS" ]; then
echo "## ❌ Pipeline Status: FAILED"
echo ""
echo "### Failed Jobs"
for job in $FAILED_JOBS; do
echo "- **$job**"
done
elif [ "${{ needs.prepare-matrix.result }}" == "success" ] && [ "${{ needs.build-artifact.result }}" == "success" ]; then
echo "## ✅ Pipeline Status: SUCCESS"
echo ""
echo "Core build jobs completed successfully."
else
echo "## ⚠️ Pipeline Status: PARTIAL"
echo ""
echo "Some jobs did not complete as expected."
fi
if [ -n "$SKIPPED_JOBS" ]; then
echo ""
echo "### ⏭️ Skipped Jobs"
for job in $SKIPPED_JOBS; do
echo "- $job"
done
fi
} >> $GITHUB_STEP_SUMMARY
- name: Environment and context information
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🌍 Environment & Context Information"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "### Workflow Inputs (if workflow_dispatch)"
echo "Force Rebuild: ${{ github.event.inputs.force_rebuild || 'N/A' }}"
echo ""
echo "### Environment Variables"
echo "CACHE_VERSION: ${{ env.CACHE_VERSION }}"
echo "TARGET_PACKAGE_NAME: ${{ env.TARGET_PACKAGE_NAME }}"
echo "ARTIFACTORY_REPOSITORY_SNAPSHOT: ${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}"
echo ""
echo "### Runner Information"
echo "OS: ${{ runner.os }}"
echo "Architecture: ${{ runner.arch }}"
echo ""
echo "### Repository Variables"
echo "DISABLE_REMOTE_TRIGGER: ${{ vars.DISABLE_REMOTE_TRIGGER || 'not set' }}"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- name: Job outputs analysis
if: always()
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📤 Job Outputs Analysis"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "### prepare-matrix outputs:"
echo "- has_apps_to_build: ${{ needs.prepare-matrix.outputs.has_apps_to_build || 'N/A' }}"
echo "- has_apps_to_restore: ${{ needs.prepare-matrix.outputs.has_apps_to_restore || 'N/A' }}"
echo ""
echo "### build-artifact outputs:"
echo "- NC_VERSION: ${{ needs.build-artifact.outputs.NC_VERSION || 'N/A' }}"
echo ""
echo "### upload-to-artifactory outputs:"
echo "- ARTIFACTORY_LAST_BUILD_PATH: ${{ needs.upload-to-artifactory.outputs.ARTIFACTORY_LAST_BUILD_PATH || 'N/A' }}"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Add to step summary
{
echo ""
echo "## 📤 Key Job Outputs"
echo ""
echo "- **NC_VERSION:** ${{ needs.build-artifact.outputs.NC_VERSION || 'N/A' }}"
echo "- **Apps to Build:** ${{ needs.prepare-matrix.outputs.has_apps_to_build || 'N/A' }}"
echo "- **Apps to Restore:** ${{ needs.prepare-matrix.outputs.has_apps_to_restore || 'N/A' }}"
echo "- **Artifactory Path:** ${{ needs.upload-to-artifactory.outputs.ARTIFACTORY_LAST_BUILD_PATH || 'N/A' }}"
} >> $GITHUB_STEP_SUMMARY