mirror of
				https://github.com/Xahau/xahaud.git
				synced 2025-11-04 10:45:50 +00:00 
			
		
		
		
	feat: replace github actions cache with s3
Replaces actions/cache with custom S3-based caching to avoid upcoming GitHub Actions cache eviction policy changes. Changes: - New S3 cache actions (xahau-ga-cache-restore/save) - zstd compression (ccache: clang=323/gcc=609 MB, Conan: clang=1.1/gcc=1.9 GB) - Immutability (first-write-wins) - Bootstrap mode (creates empty dir if no cache) Cache clearing tag: - [ci-ga-clear-cache] - Clear all caches for this job - [ci-ga-clear-cache:ccache] - Clear only ccache - [ci-ga-clear-cache:conan] - Clear only conan Configuration ordering fixes: - ccache config applied AFTER cache restore (prevents stale cached config) - Conan profile created AFTER cache restore (prevents stale cached profile) ccache improvements: - Single cache directory (~/.ccache) - Wrapper toolchain (enables ccache without affecting Conan builds) - Verbose build output (-v flag) - Fixes #620 Conan improvements: - Removed branch comparison logic for cache saves - Cache keys don't include branch names, comparison was ineffective - Fixes #618 Breaking changes: - Workflows must pass AWS credentials (aws-access-key-id, aws-secret-access-key) S3 setup: - Bucket: xahaud-github-actions-cache-niq (us-east-1) - Credentials already configured in GitHub secrets
This commit is contained in:
		@@ -1,63 +0,0 @@
 | 
			
		||||
name: 'Configure ccache'
 | 
			
		||||
description: 'Sets up ccache with consistent configuration'
 | 
			
		||||
 | 
			
		||||
inputs:
 | 
			
		||||
  max_size:
 | 
			
		||||
    description: 'Maximum cache size'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: '2G'
 | 
			
		||||
  hash_dir:
 | 
			
		||||
    description: 'Whether to include directory paths in hash'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'true'
 | 
			
		||||
  compiler_check:
 | 
			
		||||
    description: 'How to check compiler for changes'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'content'
 | 
			
		||||
  is_main_branch:
 | 
			
		||||
    description: 'Whether the current branch is the main branch'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'false'
 | 
			
		||||
  main_cache_dir:
 | 
			
		||||
    description: 'Path to the main branch cache directory'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: '~/.ccache-main'
 | 
			
		||||
  current_cache_dir:
 | 
			
		||||
    description: 'Path to the current branch cache directory'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: '~/.ccache-current'
 | 
			
		||||
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Configure ccache
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        # Create cache directories
 | 
			
		||||
        mkdir -p ${{ inputs.main_cache_dir }} ${{ inputs.current_cache_dir }}
 | 
			
		||||
        
 | 
			
		||||
        # Set compiler check globally
 | 
			
		||||
        ccache -o compiler_check=${{ inputs.compiler_check }}
 | 
			
		||||
        
 | 
			
		||||
        # Use a single config file location
 | 
			
		||||
        mkdir -p ~/.ccache
 | 
			
		||||
        export CONF_PATH="$HOME/.ccache/ccache.conf"
 | 
			
		||||
        
 | 
			
		||||
        # Apply common settings
 | 
			
		||||
        echo "max_size = ${{ inputs.max_size }}" > "$CONF_PATH"
 | 
			
		||||
        echo "hash_dir = ${{ inputs.hash_dir }}" >> "$CONF_PATH"
 | 
			
		||||
        echo "compiler_check = ${{ inputs.compiler_check }}" >> "$CONF_PATH"
 | 
			
		||||
        
 | 
			
		||||
        if [ "${{ inputs.is_main_branch }}" == "true" ]; then
 | 
			
		||||
          # Main branch: use main branch cache
 | 
			
		||||
          ccache --set-config=cache_dir="${{ inputs.main_cache_dir }}"
 | 
			
		||||
          echo "CCACHE_DIR=${{ inputs.main_cache_dir }}" >> $GITHUB_ENV
 | 
			
		||||
        else
 | 
			
		||||
          # Feature branch: use current branch cache with main as secondary
 | 
			
		||||
          ccache --set-config=cache_dir="${{ inputs.current_cache_dir }}"
 | 
			
		||||
          ccache --set-config=secondary_storage="file:${{ inputs.main_cache_dir }}"
 | 
			
		||||
          echo "CCACHE_DIR=${{ inputs.current_cache_dir }}" >> $GITHUB_ENV
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        ccache -p # Print config for verification
 | 
			
		||||
        ccache -z # Zero statistics before the build
 | 
			
		||||
							
								
								
									
										125
									
								
								.github/actions/xahau-ga-build/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								.github/actions/xahau-ga-build/action.yml
									
									
									
									
										vendored
									
									
								
							@@ -47,6 +47,24 @@ inputs:
 | 
			
		||||
    description: 'GCC version to use for Clang toolchain (e.g. 11, 13)'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
  ccache_max_size:
 | 
			
		||||
    description: 'Maximum ccache size'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: '2G'
 | 
			
		||||
  ccache_hash_dir:
 | 
			
		||||
    description: 'Whether to include directory paths in hash'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'true'
 | 
			
		||||
  ccache_compiler_check:
 | 
			
		||||
    description: 'How to check compiler for changes'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'content'
 | 
			
		||||
  aws-access-key-id:
 | 
			
		||||
    description: 'AWS Access Key ID for S3 cache storage'
 | 
			
		||||
    required: true
 | 
			
		||||
  aws-secret-access-key:
 | 
			
		||||
    description: 'AWS Secret Access Key for S3 cache storage'
 | 
			
		||||
    required: true
 | 
			
		||||
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
@@ -59,28 +77,44 @@ runs:
 | 
			
		||||
        SAFE_BRANCH=$(echo "${{ github.ref_name }}" | tr -c 'a-zA-Z0-9_.-' '-')
 | 
			
		||||
        echo "name=${SAFE_BRANCH}" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
    - name: Restore ccache directory for default branch
 | 
			
		||||
    - name: Restore ccache directory
 | 
			
		||||
      if: inputs.ccache_enabled == 'true'
 | 
			
		||||
      id: ccache-restore
 | 
			
		||||
      uses: actions/cache/restore@v4
 | 
			
		||||
      uses: ./.github/actions/xahau-ga-cache-restore
 | 
			
		||||
      with:
 | 
			
		||||
        path: ~/.ccache-main
 | 
			
		||||
        key: ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-${{ inputs.main_branch }}
 | 
			
		||||
        restore-keys: |
 | 
			
		||||
          ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-
 | 
			
		||||
          ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-
 | 
			
		||||
 | 
			
		||||
    - name: Restore ccache directory for current branch
 | 
			
		||||
      if: inputs.ccache_enabled == 'true' && steps.safe-branch.outputs.name != inputs.main_branch
 | 
			
		||||
      id: ccache-restore-current-branch
 | 
			
		||||
      uses: actions/cache/restore@v4
 | 
			
		||||
      with:
 | 
			
		||||
        path: ~/.ccache-current
 | 
			
		||||
        path: ~/.ccache
 | 
			
		||||
        key: ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-${{ steps.safe-branch.outputs.name }}
 | 
			
		||||
        restore-keys: |
 | 
			
		||||
          ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-${{ inputs.main_branch }}
 | 
			
		||||
          ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-
 | 
			
		||||
          ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-
 | 
			
		||||
        aws-access-key-id: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        aws-secret-access-key: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
 | 
			
		||||
    - name: Configure ccache
 | 
			
		||||
      if: inputs.ccache_enabled == 'true'
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        # Use ccache's default cache_dir (~/.ccache) - don't override it
 | 
			
		||||
        # This avoids tilde expansion issues when setting it explicitly
 | 
			
		||||
 | 
			
		||||
        # Create cache directory using ccache's default
 | 
			
		||||
        mkdir -p ~/.ccache
 | 
			
		||||
 | 
			
		||||
        # Configure ccache settings (but NOT cache_dir - use default)
 | 
			
		||||
        # This overwrites any cached config to ensure fresh configuration
 | 
			
		||||
        ccache --set-config=max_size=${{ inputs.ccache_max_size }}
 | 
			
		||||
        ccache --set-config=hash_dir=${{ inputs.ccache_hash_dir }}
 | 
			
		||||
        ccache --set-config=compiler_check=${{ inputs.ccache_compiler_check }}
 | 
			
		||||
 | 
			
		||||
        # Note: Not setting CCACHE_DIR - let ccache use its default (~/.ccache)
 | 
			
		||||
 | 
			
		||||
        # Print config for verification
 | 
			
		||||
        echo "=== ccache configuration ==="
 | 
			
		||||
        ccache -p
 | 
			
		||||
 | 
			
		||||
        # Zero statistics before the build
 | 
			
		||||
        ccache -z
 | 
			
		||||
 | 
			
		||||
    - name: Configure project
 | 
			
		||||
      shell: bash
 | 
			
		||||
@@ -97,11 +131,24 @@ runs:
 | 
			
		||||
          export CXX="${{ inputs.cxx }}"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        # Configure ccache launcher args
 | 
			
		||||
        CCACHE_ARGS=""
 | 
			
		||||
        # Create wrapper toolchain that overlays ccache on top of Conan's toolchain
 | 
			
		||||
        # This enables ccache for the main app build without affecting Conan dependency builds
 | 
			
		||||
        if [ "${{ inputs.ccache_enabled }}" = "true" ]; then
 | 
			
		||||
          CCACHE_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
 | 
			
		||||
          cat > wrapper_toolchain.cmake <<'EOF'
 | 
			
		||||
        # Include Conan's generated toolchain first (sets compiler, flags, etc.)
 | 
			
		||||
        # Note: CMAKE_CURRENT_LIST_DIR is the directory containing this wrapper (.build/)
 | 
			
		||||
        include(${CMAKE_CURRENT_LIST_DIR}/build/generators/conan_toolchain.cmake)
 | 
			
		||||
 | 
			
		||||
        # Overlay ccache configuration for main application build
 | 
			
		||||
        # This does NOT affect Conan dependency builds (already completed)
 | 
			
		||||
        set(CMAKE_C_COMPILER_LAUNCHER ccache CACHE STRING "C compiler launcher" FORCE)
 | 
			
		||||
        set(CMAKE_CXX_COMPILER_LAUNCHER ccache CACHE STRING "C++ compiler launcher" FORCE)
 | 
			
		||||
        EOF
 | 
			
		||||
          TOOLCHAIN_FILE="wrapper_toolchain.cmake"
 | 
			
		||||
          echo "✅ Created wrapper toolchain with ccache enabled"
 | 
			
		||||
        else
 | 
			
		||||
          TOOLCHAIN_FILE="build/generators/conan_toolchain.cmake"
 | 
			
		||||
          echo "ℹ️  Using Conan toolchain directly (ccache disabled)"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Configure C++ standard library if specified
 | 
			
		||||
@@ -143,32 +190,44 @@ runs:
 | 
			
		||||
        # So we get: .build/build/generators/ with our non-standard folder name
 | 
			
		||||
        cmake .. \
 | 
			
		||||
          -G "${{ inputs.generator }}" \
 | 
			
		||||
          $CCACHE_ARGS \
 | 
			
		||||
          ${CMAKE_CXX_FLAGS:+-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS"} \
 | 
			
		||||
          -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
 | 
			
		||||
          -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${TOOLCHAIN_FILE} \
 | 
			
		||||
          -DCMAKE_BUILD_TYPE=${{ inputs.configuration }}
 | 
			
		||||
 | 
			
		||||
    - name: Show ccache config before build
 | 
			
		||||
      if: inputs.ccache_enabled == 'true'
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "ccache configuration before build"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        ccache -p
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
    - name: Build project
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        cd ${{ inputs.build_dir }}
 | 
			
		||||
        cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc)
 | 
			
		||||
 | 
			
		||||
        # Check for verbose build flag in commit message
 | 
			
		||||
        VERBOSE_FLAG=""
 | 
			
		||||
        if echo "${XAHAU_GA_COMMIT_MSG}" | grep -q '\[ci-ga-cmake-verbose\]'; then
 | 
			
		||||
          echo "🔊 [ci-ga-cmake-verbose] detected - enabling verbose output"
 | 
			
		||||
          VERBOSE_FLAG="-- -v"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc) ${VERBOSE_FLAG}
 | 
			
		||||
 | 
			
		||||
    - name: Show ccache statistics
 | 
			
		||||
      if: inputs.ccache_enabled == 'true'
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: ccache -s
 | 
			
		||||
 | 
			
		||||
    - name: Save ccache directory for default branch
 | 
			
		||||
      if: always() && inputs.ccache_enabled == 'true' && steps.safe-branch.outputs.name == inputs.main_branch
 | 
			
		||||
      uses: actions/cache/save@v4
 | 
			
		||||
    - name: Save ccache directory
 | 
			
		||||
      if: success() && inputs.ccache_enabled == 'true'
 | 
			
		||||
      uses: ./.github/actions/xahau-ga-cache-save
 | 
			
		||||
      with:
 | 
			
		||||
        path: ~/.ccache-main
 | 
			
		||||
        key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
 | 
			
		||||
 | 
			
		||||
    - name: Save ccache directory for current branch
 | 
			
		||||
      if: always() && inputs.ccache_enabled == 'true' && steps.safe-branch.outputs.name != inputs.main_branch
 | 
			
		||||
      uses: actions/cache/save@v4
 | 
			
		||||
      with:
 | 
			
		||||
        path: ~/.ccache-current
 | 
			
		||||
        key: ${{ steps.ccache-restore-current-branch.outputs.cache-primary-key }}
 | 
			
		||||
        path: ~/.ccache
 | 
			
		||||
        key: ${{ runner.os }}-ccache-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ inputs.configuration }}-${{ steps.safe-branch.outputs.name }}
 | 
			
		||||
        aws-access-key-id: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        aws-secret-access-key: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										291
									
								
								.github/actions/xahau-ga-cache-restore/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								.github/actions/xahau-ga-cache-restore/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,291 @@
 | 
			
		||||
name: 'Xahau Cache Restore (S3)'
 | 
			
		||||
bump: 1
 | 
			
		||||
description: 'Drop-in replacement for actions/cache/restore using S3 storage'
 | 
			
		||||
 | 
			
		||||
inputs:
 | 
			
		||||
  path:
 | 
			
		||||
    description: 'A list of files, directories, and wildcard patterns to cache (currently only single path supported)'
 | 
			
		||||
    required: true
 | 
			
		||||
  key:
 | 
			
		||||
    description: 'An explicit key for restoring the cache'
 | 
			
		||||
    required: true
 | 
			
		||||
  restore-keys:
 | 
			
		||||
    description: 'An ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
  s3-bucket:
 | 
			
		||||
    description: 'S3 bucket name for cache storage'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'xahaud-github-actions-cache-niq'
 | 
			
		||||
  s3-region:
 | 
			
		||||
    description: 'S3 region'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'us-east-1'
 | 
			
		||||
  fail-on-cache-miss:
 | 
			
		||||
    description: 'Fail the workflow if cache entry is not found'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'false'
 | 
			
		||||
  lookup-only:
 | 
			
		||||
    description: 'Check if a cache entry exists for the given input(s) without downloading it'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'false'
 | 
			
		||||
  # Note: Composite actions can't access secrets.* directly - must be passed from workflow
 | 
			
		||||
  aws-access-key-id:
 | 
			
		||||
    description: 'AWS Access Key ID for S3 access'
 | 
			
		||||
    required: true
 | 
			
		||||
  aws-secret-access-key:
 | 
			
		||||
    description: 'AWS Secret Access Key for S3 access'
 | 
			
		||||
    required: true
 | 
			
		||||
 | 
			
		||||
outputs:
 | 
			
		||||
  cache-hit:
 | 
			
		||||
    description: 'A boolean value to indicate an exact match was found for the primary key'
 | 
			
		||||
    value: ${{ steps.restore-cache.outputs.cache-hit }}
 | 
			
		||||
  cache-primary-key:
 | 
			
		||||
    description: 'The key that was used to restore the cache (may be from restore-keys)'
 | 
			
		||||
    value: ${{ steps.restore-cache.outputs.cache-primary-key }}
 | 
			
		||||
  cache-matched-key:
 | 
			
		||||
    description: 'The key that was used to restore the cache (exact or prefix match)'
 | 
			
		||||
    value: ${{ steps.restore-cache.outputs.cache-matched-key }}
 | 
			
		||||
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Restore cache from S3
 | 
			
		||||
      id: restore-cache
 | 
			
		||||
      shell: bash
 | 
			
		||||
      env:
 | 
			
		||||
        AWS_ACCESS_KEY_ID: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        AWS_SECRET_ACCESS_KEY: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
        S3_BUCKET: ${{ inputs.s3-bucket }}
 | 
			
		||||
        S3_REGION: ${{ inputs.s3-region }}
 | 
			
		||||
        CACHE_KEY: ${{ inputs.key }}
 | 
			
		||||
        RESTORE_KEYS: ${{ inputs.restore-keys }}
 | 
			
		||||
        TARGET_PATH: ${{ inputs.path }}
 | 
			
		||||
        FAIL_ON_MISS: ${{ inputs.fail-on-cache-miss }}
 | 
			
		||||
        LOOKUP_ONLY: ${{ inputs.lookup-only }}
 | 
			
		||||
      run: |
 | 
			
		||||
        set -euo pipefail
 | 
			
		||||
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Xahau Cache Restore (S3)"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Target path: ${TARGET_PATH}"
 | 
			
		||||
        echo "Cache key: ${CACHE_KEY}"
 | 
			
		||||
        echo "S3 bucket: s3://${S3_BUCKET}"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Normalize target path (expand tilde)
 | 
			
		||||
        if [[ "${TARGET_PATH}" == ~* ]]; then
 | 
			
		||||
          TARGET_PATH="${HOME}${TARGET_PATH:1}"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Canonicalize path (Linux only - macOS realpath doesn't support -m)
 | 
			
		||||
        if [[ "$OSTYPE" == "linux-gnu"* ]]; then
 | 
			
		||||
          TARGET_PATH=$(realpath -m "${TARGET_PATH}")
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        echo "Normalized target path: ${TARGET_PATH}"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Debug: Show commit message
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "DEBUG: Cache clear tag detection"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Raw commit message:"
 | 
			
		||||
        echo "${XAHAU_GA_COMMIT_MSG}"
 | 
			
		||||
        echo ""
 | 
			
		||||
        echo "Searching for: [ci-ga-clear-cache] or [ci-ga-clear-cache:*]"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Check for [ci-ga-clear-cache] tag in commit message (with optional search terms)
 | 
			
		||||
        # Examples:
 | 
			
		||||
        #   [ci-ga-clear-cache]              - Clear this job's cache
 | 
			
		||||
        #   [ci-ga-clear-cache:ccache]       - Clear only if key contains "ccache"
 | 
			
		||||
        #   [ci-ga-clear-cache:gcc Debug]    - Clear only if key contains both "gcc" AND "Debug"
 | 
			
		||||
 | 
			
		||||
        # Extract search terms if present (e.g., "ccache" from "[ci-ga-clear-cache:ccache]")
 | 
			
		||||
        SEARCH_TERMS=$(echo "${XAHAU_GA_COMMIT_MSG}" | grep -o '\[ci-ga-clear-cache:[^]]*\]' | sed 's/\[ci-ga-clear-cache://;s/\]//' || echo "")
 | 
			
		||||
 | 
			
		||||
        SHOULD_CLEAR=false
 | 
			
		||||
 | 
			
		||||
        if [ -n "${SEARCH_TERMS}" ]; then
 | 
			
		||||
          # Search terms provided - check if THIS cache key matches ALL terms (AND logic)
 | 
			
		||||
          echo "🔍 [ci-ga-clear-cache:${SEARCH_TERMS}] detected"
 | 
			
		||||
          echo "Checking if cache key matches search terms..."
 | 
			
		||||
          echo "  Cache key: ${CACHE_KEY}"
 | 
			
		||||
          echo "  Search terms: ${SEARCH_TERMS}"
 | 
			
		||||
          echo ""
 | 
			
		||||
 | 
			
		||||
          MATCHES=true
 | 
			
		||||
          for term in ${SEARCH_TERMS}; do
 | 
			
		||||
            if ! echo "${CACHE_KEY}" | grep -q "${term}"; then
 | 
			
		||||
              MATCHES=false
 | 
			
		||||
              echo "  ✗ Key does not contain '${term}'"
 | 
			
		||||
              break
 | 
			
		||||
            else
 | 
			
		||||
              echo "  ✓ Key contains '${term}'"
 | 
			
		||||
            fi
 | 
			
		||||
          done
 | 
			
		||||
 | 
			
		||||
          if [ "${MATCHES}" = "true" ]; then
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "✅ Cache key matches all search terms - will clear cache"
 | 
			
		||||
            SHOULD_CLEAR=true
 | 
			
		||||
          else
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "⏭️  Cache key doesn't match search terms - skipping cache clear"
 | 
			
		||||
          fi
 | 
			
		||||
        elif echo "${XAHAU_GA_COMMIT_MSG}" | grep -q '\[ci-ga-clear-cache\]'; then
 | 
			
		||||
          # No search terms - always clear this job's cache
 | 
			
		||||
          echo "🗑️  [ci-ga-clear-cache] detected in commit message"
 | 
			
		||||
          echo "Clearing cache for key: ${CACHE_KEY}"
 | 
			
		||||
          SHOULD_CLEAR=true
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        if [ "${SHOULD_CLEAR}" = "true" ]; then
 | 
			
		||||
          echo ""
 | 
			
		||||
 | 
			
		||||
          # Delete base layer
 | 
			
		||||
          S3_BASE_KEY="s3://${S3_BUCKET}/${CACHE_KEY}-base.tar.zst"
 | 
			
		||||
          if aws s3 ls "${S3_BASE_KEY}" --region "${S3_REGION}" >/dev/null 2>&1; then
 | 
			
		||||
            echo "Deleting base layer: ${S3_BASE_KEY}"
 | 
			
		||||
            aws s3 rm "${S3_BASE_KEY}" --region "${S3_REGION}" 2>/dev/null || true
 | 
			
		||||
            echo "✓ Base layer deleted"
 | 
			
		||||
          else
 | 
			
		||||
            echo "ℹ️  No base layer found to delete"
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "✅ Cache cleared successfully"
 | 
			
		||||
          echo "Build will proceed from scratch (bootstrap mode)"
 | 
			
		||||
          echo ""
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Function to try restoring a cache key
 | 
			
		||||
        try_restore_key() {
 | 
			
		||||
          local key=$1
 | 
			
		||||
          local s3_key="s3://${S3_BUCKET}/${key}-base.tar.zst"
 | 
			
		||||
 | 
			
		||||
          echo "Checking for key: ${key}"
 | 
			
		||||
 | 
			
		||||
          if aws s3 ls "${s3_key}" --region "${S3_REGION}" >/dev/null 2>&1; then
 | 
			
		||||
            echo "✓ Found cache: ${s3_key}"
 | 
			
		||||
            return 0
 | 
			
		||||
          else
 | 
			
		||||
            echo "✗ Not found: ${key}"
 | 
			
		||||
            return 1
 | 
			
		||||
          fi
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # Try exact match first
 | 
			
		||||
        MATCHED_KEY=""
 | 
			
		||||
        EXACT_MATCH="false"
 | 
			
		||||
 | 
			
		||||
        if try_restore_key "${CACHE_KEY}"; then
 | 
			
		||||
          MATCHED_KEY="${CACHE_KEY}"
 | 
			
		||||
          EXACT_MATCH="true"
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "🎯 Exact cache hit for key: ${CACHE_KEY}"
 | 
			
		||||
        else
 | 
			
		||||
          # Try restore-keys (prefix matching)
 | 
			
		||||
          if [ -n "${RESTORE_KEYS}" ]; then
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "Primary key not found, trying restore-keys..."
 | 
			
		||||
 | 
			
		||||
            while IFS= read -r restore_key; do
 | 
			
		||||
              [ -z "${restore_key}" ] && continue
 | 
			
		||||
              restore_key=$(echo "${restore_key}" | xargs)
 | 
			
		||||
 | 
			
		||||
              if try_restore_key "${restore_key}"; then
 | 
			
		||||
                MATCHED_KEY="${restore_key}"
 | 
			
		||||
                EXACT_MATCH="false"
 | 
			
		||||
                echo ""
 | 
			
		||||
                echo "✓ Cache restored from fallback key: ${restore_key}"
 | 
			
		||||
                break
 | 
			
		||||
              fi
 | 
			
		||||
            done <<< "${RESTORE_KEYS}"
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Check if we found anything
 | 
			
		||||
        if [ -z "${MATCHED_KEY}" ]; then
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "❌ No cache found for key: ${CACHE_KEY}"
 | 
			
		||||
 | 
			
		||||
          if [ "${FAIL_ON_MISS}" = "true" ]; then
 | 
			
		||||
            echo "fail-on-cache-miss is enabled, failing workflow"
 | 
			
		||||
            exit 1
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          # Set outputs for cache miss
 | 
			
		||||
          echo "cache-hit=false" >> $GITHUB_OUTPUT
 | 
			
		||||
          echo "cache-primary-key=" >> $GITHUB_OUTPUT
 | 
			
		||||
          echo "cache-matched-key=" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
          # Create empty cache directory
 | 
			
		||||
          mkdir -p "${TARGET_PATH}"
 | 
			
		||||
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          echo "Cache restore completed (bootstrap mode)"
 | 
			
		||||
          echo "Created empty cache directory: ${TARGET_PATH}"
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          exit 0
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # If lookup-only, we're done
 | 
			
		||||
        if [ "${LOOKUP_ONLY}" = "true" ]; then
 | 
			
		||||
          echo "cache-hit=${EXACT_MATCH}" >> $GITHUB_OUTPUT
 | 
			
		||||
          echo "cache-primary-key=${CACHE_KEY}" >> $GITHUB_OUTPUT
 | 
			
		||||
          echo "cache-matched-key=${MATCHED_KEY}" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          echo "Cache lookup completed (lookup-only mode)"
 | 
			
		||||
          echo "Cache exists: ${MATCHED_KEY}"
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          exit 0
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Download and extract cache
 | 
			
		||||
        S3_KEY="s3://${S3_BUCKET}/${MATCHED_KEY}-base.tar.zst"
 | 
			
		||||
        TEMP_TARBALL="/tmp/xahau-cache-restore-$$.tar.zst"
 | 
			
		||||
 | 
			
		||||
        echo ""
 | 
			
		||||
        echo "Downloading cache..."
 | 
			
		||||
        aws s3 cp "${S3_KEY}" "${TEMP_TARBALL}" --region "${S3_REGION}" --no-progress
 | 
			
		||||
 | 
			
		||||
        TARBALL_SIZE=$(du -h "${TEMP_TARBALL}" | cut -f1)
 | 
			
		||||
        echo "✓ Downloaded: ${TARBALL_SIZE}"
 | 
			
		||||
 | 
			
		||||
        # Create parent directory if needed
 | 
			
		||||
        mkdir -p "$(dirname "${TARGET_PATH}")"
 | 
			
		||||
 | 
			
		||||
        # Remove existing target if it exists
 | 
			
		||||
        if [ -e "${TARGET_PATH}" ]; then
 | 
			
		||||
          echo "Removing existing target: ${TARGET_PATH}"
 | 
			
		||||
          rm -rf "${TARGET_PATH}"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Create target directory and extract
 | 
			
		||||
        mkdir -p "${TARGET_PATH}"
 | 
			
		||||
        echo ""
 | 
			
		||||
        echo "Extracting cache..."
 | 
			
		||||
        zstd -d -c "${TEMP_TARBALL}" | tar -xf - -C "${TARGET_PATH}"
 | 
			
		||||
        echo "✓ Cache extracted to: ${TARGET_PATH}"
 | 
			
		||||
 | 
			
		||||
        # Cleanup
 | 
			
		||||
        rm -f "${TEMP_TARBALL}"
 | 
			
		||||
 | 
			
		||||
        # Set outputs
 | 
			
		||||
        echo "cache-hit=${EXACT_MATCH}" >> $GITHUB_OUTPUT
 | 
			
		||||
        echo "cache-primary-key=${CACHE_KEY}" >> $GITHUB_OUTPUT
 | 
			
		||||
        echo "cache-matched-key=${MATCHED_KEY}" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
        echo ""
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Cache restore completed successfully"
 | 
			
		||||
        echo "Cache hit: ${EXACT_MATCH}"
 | 
			
		||||
        echo "Matched key: ${MATCHED_KEY}"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
							
								
								
									
										110
									
								
								.github/actions/xahau-ga-cache-save/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								.github/actions/xahau-ga-cache-save/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
name: 'Xahau Cache Save (S3)'
 | 
			
		||||
description: 'Drop-in replacement for actions/cache/save using S3 storage'
 | 
			
		||||
 | 
			
		||||
inputs:
 | 
			
		||||
  path:
 | 
			
		||||
    description: 'A list of files, directories, and wildcard patterns to cache (currently only single path supported)'
 | 
			
		||||
    required: true
 | 
			
		||||
  key:
 | 
			
		||||
    description: 'An explicit key for saving the cache'
 | 
			
		||||
    required: true
 | 
			
		||||
  s3-bucket:
 | 
			
		||||
    description: 'S3 bucket name for cache storage'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'xahaud-github-actions-cache-niq'
 | 
			
		||||
  s3-region:
 | 
			
		||||
    description: 'S3 region'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'us-east-1'
 | 
			
		||||
  # Note: Composite actions can't access secrets.* directly - must be passed from workflow
 | 
			
		||||
  aws-access-key-id:
 | 
			
		||||
    description: 'AWS Access Key ID for S3 access'
 | 
			
		||||
    required: true
 | 
			
		||||
  aws-secret-access-key:
 | 
			
		||||
    description: 'AWS Secret Access Key for S3 access'
 | 
			
		||||
    required: true
 | 
			
		||||
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Save cache to S3
 | 
			
		||||
      shell: bash
 | 
			
		||||
      env:
 | 
			
		||||
        AWS_ACCESS_KEY_ID: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        AWS_SECRET_ACCESS_KEY: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
        S3_BUCKET: ${{ inputs.s3-bucket }}
 | 
			
		||||
        S3_REGION: ${{ inputs.s3-region }}
 | 
			
		||||
        CACHE_KEY: ${{ inputs.key }}
 | 
			
		||||
        TARGET_PATH: ${{ inputs.path }}
 | 
			
		||||
      run: |
 | 
			
		||||
        set -euo pipefail
 | 
			
		||||
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Xahau Cache Save (S3)"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Target path: ${TARGET_PATH}"
 | 
			
		||||
        echo "Cache key: ${CACHE_KEY}"
 | 
			
		||||
        echo "S3 bucket: s3://${S3_BUCKET}"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Normalize target path (expand tilde and resolve to absolute path)
 | 
			
		||||
        if [[ "${TARGET_PATH}" == ~* ]]; then
 | 
			
		||||
          TARGET_PATH="${HOME}${TARGET_PATH:1}"
 | 
			
		||||
        fi
 | 
			
		||||
        echo "Normalized target path: ${TARGET_PATH}"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Check if target directory exists
 | 
			
		||||
        if [ ! -d "${TARGET_PATH}" ]; then
 | 
			
		||||
          echo "⚠️  Target directory does not exist: ${TARGET_PATH}"
 | 
			
		||||
          echo "Skipping cache save."
 | 
			
		||||
          exit 0
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Use static base name (one base per key, immutable)
 | 
			
		||||
        S3_BASE_KEY="s3://${S3_BUCKET}/${CACHE_KEY}-base.tar.zst"
 | 
			
		||||
 | 
			
		||||
        # Check if base already exists (immutability - first write wins)
 | 
			
		||||
        if aws s3 ls "${S3_BASE_KEY}" --region "${S3_REGION}" >/dev/null 2>&1; then
 | 
			
		||||
          echo "⚠️  Cache already exists: ${S3_BASE_KEY}"
 | 
			
		||||
          echo "Skipping upload (immutability - first write wins, like GitHub Actions)"
 | 
			
		||||
          echo ""
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          echo "Cache save completed (already exists)"
 | 
			
		||||
          echo "=========================================="
 | 
			
		||||
          exit 0
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Create tarball
 | 
			
		||||
        BASE_TARBALL="/tmp/xahau-cache-base-$$.tar.zst"
 | 
			
		||||
 | 
			
		||||
        echo "Creating cache tarball..."
 | 
			
		||||
        tar -cf - -C "${TARGET_PATH}" . | zstd -3 -T0 -q -o "${BASE_TARBALL}"
 | 
			
		||||
 | 
			
		||||
        BASE_SIZE=$(du -h "${BASE_TARBALL}" | cut -f1)
 | 
			
		||||
        echo "✓ Cache tarball created: ${BASE_SIZE}"
 | 
			
		||||
        echo ""
 | 
			
		||||
 | 
			
		||||
        # Upload to S3
 | 
			
		||||
        echo "Uploading cache to S3..."
 | 
			
		||||
        echo "  Key: ${CACHE_KEY}-base.tar.zst"
 | 
			
		||||
 | 
			
		||||
        aws s3api put-object \
 | 
			
		||||
          --bucket "${S3_BUCKET}" \
 | 
			
		||||
          --key "${CACHE_KEY}-base.tar.zst" \
 | 
			
		||||
          --body "${BASE_TARBALL}" \
 | 
			
		||||
          --tagging 'type=base' \
 | 
			
		||||
          --region "${S3_REGION}" \
 | 
			
		||||
          >/dev/null 2>&1
 | 
			
		||||
 | 
			
		||||
        echo "✓ Uploaded: ${S3_BASE_KEY}"
 | 
			
		||||
 | 
			
		||||
        # Cleanup
 | 
			
		||||
        rm -f "${BASE_TARBALL}"
 | 
			
		||||
 | 
			
		||||
        echo ""
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
        echo "Cache save completed successfully"
 | 
			
		||||
        echo "Cache size: ${BASE_SIZE}"
 | 
			
		||||
        echo "Cache key: ${CACHE_KEY}"
 | 
			
		||||
        echo "=========================================="
 | 
			
		||||
							
								
								
									
										127
									
								
								.github/actions/xahau-ga-dependencies/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										127
									
								
								.github/actions/xahau-ga-dependencies/action.yml
									
									
									
									
										vendored
									
									
								
							@@ -25,6 +25,28 @@ inputs:
 | 
			
		||||
    description: 'Main branch name for restore keys'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'dev'
 | 
			
		||||
  os:
 | 
			
		||||
    description: 'Operating system (Linux, Macos)'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'Linux'
 | 
			
		||||
  arch:
 | 
			
		||||
    description: 'Architecture (x86_64, armv8)'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: 'x86_64'
 | 
			
		||||
  compiler:
 | 
			
		||||
    description: 'Compiler type (gcc, clang, apple-clang)'
 | 
			
		||||
    required: true
 | 
			
		||||
  compiler_version:
 | 
			
		||||
    description: 'Compiler version (11, 13, 14, etc.)'
 | 
			
		||||
    required: true
 | 
			
		||||
  cc:
 | 
			
		||||
    description: 'C compiler executable (gcc-13, clang-14, etc.), empty for macOS'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
  cxx:
 | 
			
		||||
    description: 'C++ compiler executable (g++-14, clang++-14, etc.), empty for macOS'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
  stdlib:
 | 
			
		||||
    description: 'C++ standard library for Conan configuration (note: also in compiler-id)'
 | 
			
		||||
    required: true
 | 
			
		||||
@@ -32,6 +54,12 @@ inputs:
 | 
			
		||||
    options:
 | 
			
		||||
      - libstdcxx
 | 
			
		||||
      - libcxx
 | 
			
		||||
  aws-access-key-id:
 | 
			
		||||
    description: 'AWS Access Key ID for S3 cache storage'
 | 
			
		||||
    required: true
 | 
			
		||||
  aws-secret-access-key:
 | 
			
		||||
    description: 'AWS Secret Access Key for S3 cache storage'
 | 
			
		||||
    required: true
 | 
			
		||||
 | 
			
		||||
outputs:
 | 
			
		||||
  cache-hit:
 | 
			
		||||
@@ -41,47 +69,72 @@ outputs:
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Generate safe branch name
 | 
			
		||||
      if: inputs.cache_enabled == 'true'
 | 
			
		||||
      id: safe-branch
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        SAFE_BRANCH=$(echo "${{ github.ref_name }}" | tr -c 'a-zA-Z0-9_.-' '-')
 | 
			
		||||
        echo "name=${SAFE_BRANCH}" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
    - name: Check conanfile changes
 | 
			
		||||
      if: inputs.cache_enabled == 'true'
 | 
			
		||||
      id: check-conanfile-changes
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        # Check if we're on the main branch
 | 
			
		||||
        if [ "${{ github.ref_name }}" == "${{ inputs.main_branch }}" ]; then
 | 
			
		||||
          echo "should-save-conan-cache=true" >> $GITHUB_OUTPUT
 | 
			
		||||
        else
 | 
			
		||||
          # Fetch main branch for comparison
 | 
			
		||||
          git fetch origin ${{ inputs.main_branch }}
 | 
			
		||||
          
 | 
			
		||||
          # Check if conanfile.txt or conanfile.py has changed compared to main branch
 | 
			
		||||
          if git diff --quiet origin/${{ inputs.main_branch }}..HEAD -- '**/conanfile.txt' '**/conanfile.py'; then
 | 
			
		||||
            echo "should-save-conan-cache=false" >> $GITHUB_OUTPUT
 | 
			
		||||
          else
 | 
			
		||||
            echo "should-save-conan-cache=true" >> $GITHUB_OUTPUT
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
    - name: Restore Conan cache
 | 
			
		||||
      if: inputs.cache_enabled == 'true'
 | 
			
		||||
      id: cache-restore-conan
 | 
			
		||||
      uses: actions/cache/restore@v4
 | 
			
		||||
      uses: ./.github/actions/xahau-ga-cache-restore
 | 
			
		||||
      with:
 | 
			
		||||
        path: |
 | 
			
		||||
          ~/.conan
 | 
			
		||||
          ~/.conan2
 | 
			
		||||
        path: ~/.conan2
 | 
			
		||||
        # Note: compiler-id format is compiler-version-stdlib[-gccversion]
 | 
			
		||||
        key: ${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ hashFiles('**/conanfile.txt', '**/conanfile.py') }}-${{ inputs.configuration }}
 | 
			
		||||
        restore-keys: |
 | 
			
		||||
          ${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ hashFiles('**/conanfile.txt', '**/conanfile.py') }}-
 | 
			
		||||
          ${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-
 | 
			
		||||
        aws-access-key-id: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        aws-secret-access-key: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
 | 
			
		||||
    - name: Configure Conan
 | 
			
		||||
      shell: bash
 | 
			
		||||
      run: |
 | 
			
		||||
        # Create the default profile directory if it doesn't exist
 | 
			
		||||
        mkdir -p ~/.conan2/profiles
 | 
			
		||||
 | 
			
		||||
        # Determine the correct libcxx based on stdlib parameter
 | 
			
		||||
        if [ "${{ inputs.stdlib }}" = "libcxx" ]; then
 | 
			
		||||
          LIBCXX="libc++"
 | 
			
		||||
        else
 | 
			
		||||
          LIBCXX="libstdc++11"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Create profile with our specific settings
 | 
			
		||||
        # This overwrites any cached profile to ensure fresh configuration
 | 
			
		||||
        cat > ~/.conan2/profiles/default <<EOF
 | 
			
		||||
        [settings]
 | 
			
		||||
        arch=${{ inputs.arch }}
 | 
			
		||||
        build_type=${{ inputs.configuration }}
 | 
			
		||||
        compiler=${{ inputs.compiler }}
 | 
			
		||||
        compiler.cppstd=20
 | 
			
		||||
        compiler.libcxx=${LIBCXX}
 | 
			
		||||
        compiler.version=${{ inputs.compiler_version }}
 | 
			
		||||
        os=${{ inputs.os }}
 | 
			
		||||
        EOF
 | 
			
		||||
 | 
			
		||||
        # Add buildenv and conf sections for Linux (not needed for macOS)
 | 
			
		||||
        if [ "${{ inputs.os }}" = "Linux" ] && [ -n "${{ inputs.cc }}" ]; then
 | 
			
		||||
          cat >> ~/.conan2/profiles/default <<EOF
 | 
			
		||||
 | 
			
		||||
        [buildenv]
 | 
			
		||||
        CC=/usr/bin/${{ inputs.cc }}
 | 
			
		||||
        CXX=/usr/bin/${{ inputs.cxx }}
 | 
			
		||||
 | 
			
		||||
        [conf]
 | 
			
		||||
        tools.build:compiler_executables={"c": "/usr/bin/${{ inputs.cc }}", "cpp": "/usr/bin/${{ inputs.cxx }}"}
 | 
			
		||||
        EOF
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Add macOS-specific conf if needed
 | 
			
		||||
        if [ "${{ inputs.os }}" = "Macos" ]; then
 | 
			
		||||
          cat >> ~/.conan2/profiles/default <<EOF
 | 
			
		||||
 | 
			
		||||
        [conf]
 | 
			
		||||
        # Workaround for gRPC with newer Apple Clang
 | 
			
		||||
        tools.build:cxxflags=["-Wno-missing-template-arg-list-after-template-kw"]
 | 
			
		||||
        EOF
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Display profile for verification
 | 
			
		||||
        conan profile show
 | 
			
		||||
 | 
			
		||||
    - name: Export custom recipes
 | 
			
		||||
      shell: bash
 | 
			
		||||
@@ -107,10 +160,10 @@ runs:
 | 
			
		||||
          ..
 | 
			
		||||
 | 
			
		||||
    - name: Save Conan cache
 | 
			
		||||
      if: always() && inputs.cache_enabled == 'true' && steps.cache-restore-conan.outputs.cache-hit != 'true' && steps.check-conanfile-changes.outputs.should-save-conan-cache == 'true'
 | 
			
		||||
      uses: actions/cache/save@v4
 | 
			
		||||
      if: success() && inputs.cache_enabled == 'true' && steps.cache-restore-conan.outputs.cache-hit != 'true'
 | 
			
		||||
      uses: ./.github/actions/xahau-ga-cache-save
 | 
			
		||||
      with:
 | 
			
		||||
        path: |
 | 
			
		||||
          ~/.conan
 | 
			
		||||
          ~/.conan2
 | 
			
		||||
        key: ${{ steps.cache-restore-conan.outputs.cache-primary-key }}
 | 
			
		||||
        path: ~/.conan2
 | 
			
		||||
        key: ${{ runner.os }}-conan-v${{ inputs.cache_version }}-${{ inputs.compiler-id }}-${{ hashFiles('**/conanfile.txt', '**/conanfile.py') }}-${{ inputs.configuration }}
 | 
			
		||||
        aws-access-key-id: ${{ inputs.aws-access-key-id }}
 | 
			
		||||
        aws-secret-access-key: ${{ inputs.aws-secret-access-key }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								.github/actions/xahau-ga-get-commit-message/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								.github/actions/xahau-ga-get-commit-message/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
name: 'Get Commit Message'
 | 
			
		||||
description: 'Gets commit message for both push and pull_request events and sets XAHAU_GA_COMMIT_MSG env var'
 | 
			
		||||
 | 
			
		||||
inputs:
 | 
			
		||||
  event-name:
 | 
			
		||||
    description: 'The event name (push or pull_request)'
 | 
			
		||||
    required: true
 | 
			
		||||
  head-commit-message:
 | 
			
		||||
    description: 'The head commit message (for push events)'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
  pr-head-sha:
 | 
			
		||||
    description: 'The PR head SHA (for pull_request events)'
 | 
			
		||||
    required: false
 | 
			
		||||
    default: ''
 | 
			
		||||
 | 
			
		||||
runs:
 | 
			
		||||
  using: 'composite'
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Get commit message and set environment variable
 | 
			
		||||
      shell: python
 | 
			
		||||
      run: |
 | 
			
		||||
        import os
 | 
			
		||||
        import subprocess
 | 
			
		||||
        import secrets
 | 
			
		||||
 | 
			
		||||
        event_name = "${{ inputs.event-name }}"
 | 
			
		||||
        pr_head_sha = "${{ inputs.pr-head-sha }}"
 | 
			
		||||
 | 
			
		||||
        print("==========================================")
 | 
			
		||||
        print("Setting XAHAU_GA_COMMIT_MSG environment variable")
 | 
			
		||||
        print("==========================================")
 | 
			
		||||
        print(f"Event: {event_name}")
 | 
			
		||||
 | 
			
		||||
        if event_name == 'push':
 | 
			
		||||
            # For push events, use the input directly
 | 
			
		||||
            message = """${{ inputs.head-commit-message }}"""
 | 
			
		||||
            print("Source: workflow input (github.event.head_commit.message)")
 | 
			
		||||
        elif event_name == 'pull_request':
 | 
			
		||||
            # For PR events, fetch the specific SHA
 | 
			
		||||
            print(f"Source: git show {pr_head_sha} (fetching PR head commit)")
 | 
			
		||||
 | 
			
		||||
            # Fetch the PR head commit
 | 
			
		||||
            subprocess.run(
 | 
			
		||||
                ['git', 'fetch', 'origin', pr_head_sha],
 | 
			
		||||
                check=True
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # Get commit message from the fetched SHA
 | 
			
		||||
            result = subprocess.run(
 | 
			
		||||
                ['git', 'show', '-s', '--format=%B', pr_head_sha],
 | 
			
		||||
                capture_output=True,
 | 
			
		||||
                text=True,
 | 
			
		||||
                check=True
 | 
			
		||||
            )
 | 
			
		||||
            message = result.stdout.strip()
 | 
			
		||||
        else:
 | 
			
		||||
            message = ""
 | 
			
		||||
            print(f"Warning: Unknown event type: {event_name}")
 | 
			
		||||
 | 
			
		||||
        print(f"Commit message (first 100 chars): {message[:100]}")
 | 
			
		||||
 | 
			
		||||
        # Write to GITHUB_ENV using heredoc with random delimiter (prevents injection attacks)
 | 
			
		||||
        # See: https://securitylab.github.com/resources/github-actions-untrusted-input/
 | 
			
		||||
        delimiter = f"EOF_{secrets.token_hex(16)}"
 | 
			
		||||
 | 
			
		||||
        with open(os.environ['GITHUB_ENV'], 'a') as f:
 | 
			
		||||
            f.write(f'XAHAU_GA_COMMIT_MSG<<{delimiter}\n')
 | 
			
		||||
            f.write(message)
 | 
			
		||||
            f.write(f'\n{delimiter}\n')
 | 
			
		||||
 | 
			
		||||
        print(f"✓ XAHAU_GA_COMMIT_MSG set (available to all subsequent steps)")
 | 
			
		||||
        print("==========================================")
 | 
			
		||||
							
								
								
									
										54
									
								
								.github/workflows/xahau-ga-macos.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								.github/workflows/xahau-ga-macos.yml
									
									
									
									
										vendored
									
									
								
							@@ -30,6 +30,14 @@ jobs:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
 | 
			
		||||
      - name: Get commit message
 | 
			
		||||
        id: get-commit-message
 | 
			
		||||
        uses: ./.github/actions/xahau-ga-get-commit-message
 | 
			
		||||
        with:
 | 
			
		||||
          event-name: ${{ github.event_name }}
 | 
			
		||||
          head-commit-message: ${{ github.event.head_commit.message }}
 | 
			
		||||
          pr-head-sha: ${{ github.event.pull_request.head.sha }}
 | 
			
		||||
 | 
			
		||||
      - name: Install Conan
 | 
			
		||||
        run: |
 | 
			
		||||
          brew install conan
 | 
			
		||||
@@ -78,14 +86,6 @@ jobs:
 | 
			
		||||
      - name: Install ccache
 | 
			
		||||
        run: brew install ccache
 | 
			
		||||
 | 
			
		||||
      - name: Configure ccache
 | 
			
		||||
        uses: ./.github/actions/xahau-configure-ccache
 | 
			
		||||
        with:
 | 
			
		||||
          max_size: 2G
 | 
			
		||||
          hash_dir: true
 | 
			
		||||
          compiler_check: content
 | 
			
		||||
          is_main_branch: ${{ github.ref_name == env.MAIN_BRANCH_NAME }}
 | 
			
		||||
 | 
			
		||||
      - name: Check environment
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "PATH:"
 | 
			
		||||
@@ -98,32 +98,12 @@ jobs:
 | 
			
		||||
          echo "---- Full Environment ----"
 | 
			
		||||
          env
 | 
			
		||||
 | 
			
		||||
      - name: Configure Conan
 | 
			
		||||
      - name: Detect compiler version
 | 
			
		||||
        id: detect-compiler
 | 
			
		||||
        run: |
 | 
			
		||||
          # Create the default profile directory if it doesn't exist
 | 
			
		||||
          mkdir -p ~/.conan2/profiles
 | 
			
		||||
 | 
			
		||||
          # Detect compiler version
 | 
			
		||||
          COMPILER_VERSION=$(clang --version | grep -oE 'version [0-9]+' | grep -oE '[0-9]+')
 | 
			
		||||
 | 
			
		||||
          # Create profile with our specific settings
 | 
			
		||||
          cat > ~/.conan2/profiles/default <<EOF
 | 
			
		||||
          [settings]
 | 
			
		||||
          arch=armv8
 | 
			
		||||
          build_type=Release
 | 
			
		||||
          compiler=apple-clang
 | 
			
		||||
          compiler.cppstd=20
 | 
			
		||||
          compiler.libcxx=libc++
 | 
			
		||||
          compiler.version=${COMPILER_VERSION}
 | 
			
		||||
          os=Macos
 | 
			
		||||
 | 
			
		||||
          [conf]
 | 
			
		||||
          # Workaround for gRPC with newer Apple Clang
 | 
			
		||||
          tools.build:cxxflags=["-Wno-missing-template-arg-list-after-template-kw"]
 | 
			
		||||
          EOF
 | 
			
		||||
 | 
			
		||||
          # Display profile for verification
 | 
			
		||||
          conan profile show
 | 
			
		||||
          echo "compiler_version=${COMPILER_VERSION}" >> $GITHUB_OUTPUT
 | 
			
		||||
          echo "Detected Apple Clang version: ${COMPILER_VERSION}"
 | 
			
		||||
 | 
			
		||||
      - name: Install dependencies
 | 
			
		||||
        uses: ./.github/actions/xahau-ga-dependencies
 | 
			
		||||
@@ -133,6 +113,13 @@ jobs:
 | 
			
		||||
          compiler-id: clang
 | 
			
		||||
          cache_version: ${{ env.CACHE_VERSION }}
 | 
			
		||||
          main_branch: ${{ env.MAIN_BRANCH_NAME }}
 | 
			
		||||
          os: Macos
 | 
			
		||||
          arch: armv8
 | 
			
		||||
          compiler: apple-clang
 | 
			
		||||
          compiler_version: ${{ steps.detect-compiler.outputs.compiler_version }}
 | 
			
		||||
          stdlib: libcxx
 | 
			
		||||
          aws-access-key-id: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_KEY_ID }}
 | 
			
		||||
          aws-secret-access-key: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_ACCESS_KEY }}
 | 
			
		||||
 | 
			
		||||
      - name: Build
 | 
			
		||||
        uses: ./.github/actions/xahau-ga-build
 | 
			
		||||
@@ -143,6 +130,9 @@ jobs:
 | 
			
		||||
          compiler-id: clang
 | 
			
		||||
          cache_version: ${{ env.CACHE_VERSION }}
 | 
			
		||||
          main_branch: ${{ env.MAIN_BRANCH_NAME }}
 | 
			
		||||
          stdlib: libcxx
 | 
			
		||||
          aws-access-key-id: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_KEY_ID }}
 | 
			
		||||
          aws-secret-access-key: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_ACCESS_KEY }}
 | 
			
		||||
 | 
			
		||||
      - name: Test
 | 
			
		||||
        run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								.github/workflows/xahau-ga-nix.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								.github/workflows/xahau-ga-nix.yml
									
									
									
									
										vendored
									
									
								
							@@ -2,7 +2,7 @@ name: Nix - GA Runner
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches: ["dev", "candidate", "release"]
 | 
			
		||||
    branches: ["dev", "candidate", "release", "nd-experiment-overlayfs-2025-10-29"]
 | 
			
		||||
  pull_request:
 | 
			
		||||
    branches: ["dev", "candidate", "release"]
 | 
			
		||||
  schedule:
 | 
			
		||||
@@ -156,12 +156,20 @@ jobs:
 | 
			
		||||
    env:
 | 
			
		||||
      build_dir: .build
 | 
			
		||||
      # Bump this number to invalidate all caches globally.
 | 
			
		||||
      CACHE_VERSION: 2
 | 
			
		||||
      CACHE_VERSION: 3
 | 
			
		||||
      MAIN_BRANCH_NAME: dev
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
 | 
			
		||||
      - name: Get commit message
 | 
			
		||||
        id: get-commit-message
 | 
			
		||||
        uses: ./.github/actions/xahau-ga-get-commit-message
 | 
			
		||||
        with:
 | 
			
		||||
          event-name: ${{ github.event_name }}
 | 
			
		||||
          head-commit-message: ${{ github.event.head_commit.message }}
 | 
			
		||||
          pr-head-sha: ${{ github.event.pull_request.head.sha }}
 | 
			
		||||
 | 
			
		||||
      - name: Install build dependencies
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo apt-get update
 | 
			
		||||
@@ -231,48 +239,6 @@ jobs:
 | 
			
		||||
          # Install Conan 2
 | 
			
		||||
          pip install --upgrade "conan>=2.0,<3"
 | 
			
		||||
 | 
			
		||||
      - name: Configure ccache
 | 
			
		||||
        uses: ./.github/actions/xahau-configure-ccache
 | 
			
		||||
        with:
 | 
			
		||||
          max_size: 2G
 | 
			
		||||
          hash_dir: true
 | 
			
		||||
          compiler_check: content
 | 
			
		||||
          is_main_branch: ${{ github.ref_name == env.MAIN_BRANCH_NAME }}
 | 
			
		||||
 | 
			
		||||
      - name: Configure Conan
 | 
			
		||||
        run: |
 | 
			
		||||
          # Create the default profile directory if it doesn't exist
 | 
			
		||||
          mkdir -p ~/.conan2/profiles
 | 
			
		||||
 | 
			
		||||
          # Determine the correct libcxx based on stdlib parameter
 | 
			
		||||
          if [ "${{ matrix.stdlib }}" = "libcxx" ]; then
 | 
			
		||||
            LIBCXX="libc++"
 | 
			
		||||
          else
 | 
			
		||||
            LIBCXX="libstdc++11"
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          # Create profile with our specific settings
 | 
			
		||||
          cat > ~/.conan2/profiles/default <<EOF
 | 
			
		||||
          [settings]
 | 
			
		||||
          arch=x86_64
 | 
			
		||||
          build_type=${{ matrix.configuration }}
 | 
			
		||||
          compiler=${{ matrix.compiler }}
 | 
			
		||||
          compiler.cppstd=20
 | 
			
		||||
          compiler.libcxx=${LIBCXX}
 | 
			
		||||
          compiler.version=${{ matrix.compiler_version }}
 | 
			
		||||
          os=Linux
 | 
			
		||||
 | 
			
		||||
          [buildenv]
 | 
			
		||||
          CC=/usr/bin/${{ matrix.cc }}
 | 
			
		||||
          CXX=/usr/bin/${{ matrix.cxx }}
 | 
			
		||||
 | 
			
		||||
          [conf]
 | 
			
		||||
          tools.build:compiler_executables={"c": "/usr/bin/${{ matrix.cc }}", "cpp": "/usr/bin/${{ matrix.cxx }}"}
 | 
			
		||||
          EOF
 | 
			
		||||
 | 
			
		||||
          # Display profile for verification
 | 
			
		||||
          conan profile show
 | 
			
		||||
 | 
			
		||||
      - name: Check environment
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "PATH:"
 | 
			
		||||
@@ -293,7 +259,13 @@ jobs:
 | 
			
		||||
          compiler-id: ${{ matrix.compiler_id }}
 | 
			
		||||
          cache_version: ${{ env.CACHE_VERSION }}
 | 
			
		||||
          main_branch: ${{ env.MAIN_BRANCH_NAME }}
 | 
			
		||||
          compiler: ${{ matrix.compiler }}
 | 
			
		||||
          compiler_version: ${{ matrix.compiler_version }}
 | 
			
		||||
          cc: ${{ matrix.cc }}
 | 
			
		||||
          cxx: ${{ matrix.cxx }}
 | 
			
		||||
          stdlib: ${{ matrix.stdlib }}
 | 
			
		||||
          aws-access-key-id: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_KEY_ID }}
 | 
			
		||||
          aws-secret-access-key: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_ACCESS_KEY }}
 | 
			
		||||
 | 
			
		||||
      - name: Build
 | 
			
		||||
        uses: ./.github/actions/xahau-ga-build
 | 
			
		||||
@@ -308,6 +280,8 @@ jobs:
 | 
			
		||||
          main_branch: ${{ env.MAIN_BRANCH_NAME }}
 | 
			
		||||
          stdlib: ${{ matrix.stdlib }}
 | 
			
		||||
          clang_gcc_toolchain: ${{ matrix.clang_gcc_toolchain || '' }}
 | 
			
		||||
          aws-access-key-id: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_KEY_ID }}
 | 
			
		||||
          aws-secret-access-key: ${{ secrets.XAHAUD_GITHUB_ACTIONS_CACHE_NIQ_AWS_ACCESS_KEY }}
 | 
			
		||||
 | 
			
		||||
      - name: Set artifact name
 | 
			
		||||
        id: set-artifact-name
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user