name: Sync CMP Directories on: workflow_dispatch: inputs: upstream: description: 'Upstream repository to sync directories from' default: 'https://github.com/openMF/kmp-project-template.git' required: true type: string schedule: - cron: '0 0 * * 1' jobs: sync-directories: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 ref: dev - name: Setup Git config run: | git config --global user.name "github-actions[bot]" git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Add upstream remote and fetch run: | git remote add upstream ${{ inputs.upstream }} || true git fetch upstream || exit 1 - name: Check upstream/dev exists run: | if ! git rev-parse --verify upstream/dev >/dev/null 2>&1; then echo "Error: upstream/dev branch does not exist" exit 1 fi - name: Create and checkout temporary branch run: | TEMP_BRANCH="temp-sync-branch-${{ github.run_number }}" git checkout -b "$TEMP_BRANCH" upstream/dev || exit 1 echo "TEMP_BRANCH=$TEMP_BRANCH" >> $GITHUB_ENV - name: Sync directories and files run: | # Declare directories and files to sync DIRS=( "cmp-android" "cmp-desktop" "cmp-ios" "cmp-web" "cmp-shared" "core-base" "build-logic" "fastlane" "scripts" "config" ".github" ".run" ) FILES=( "Gemfile" "Gemfile.lock" "ci-prepush.bat" "ci-prepush.sh" ) # Define exclusions declare -A EXCLUSIONS=( ["cmp-android"]="src/main/res dependencies src/main/ic_launcher-playstore.png google-services.json" ["cmp-web"]="src/jsMain/resources src/wasmJsMain/resources" ["cmp-desktop"]="icons" ["cmp-ios"]="iosApp/Assets.xcassets" ["root"]="secrets.env" ) # Function to check if path should be excluded should_exclude() { local dir=$1 local path=$2 # Check for root exclusions if [[ "$dir" == "." && -n "${EXCLUSIONS["root"]}" ]]; then local root_excluded_paths=(${EXCLUSIONS["root"]}) for excluded in "${root_excluded_paths[@]}"; do if [[ "$path" == *"$excluded"* ]]; then return 0 fi done fi # Check directory-specific exclusions if [[ -n "${EXCLUSIONS[$dir]}" ]]; then local excluded_paths=(${EXCLUSIONS[$dir]}) for excluded in "${excluded_paths[@]}"; do if [[ "$path" == *"$excluded"* ]]; then return 0 fi done fi return 1 } # Function to preserve excluded paths preserve_excluded() { local dir=$1 if [[ -n "${EXCLUSIONS[$dir]}" ]]; then local excluded_paths=(${EXCLUSIONS[$dir]}) for excluded in "${excluded_paths[@]}"; do local full_path="$dir/$excluded" if [[ -e "$full_path" ]]; then echo "Preserving excluded path: $full_path" local temp_path="temp_excluded/$full_path" mkdir -p "$(dirname "$temp_path")" cp -r "$full_path" "$(dirname "$temp_path")" fi done fi } # Function to restore excluded paths restore_excluded() { local dir=$1 if [[ -n "${EXCLUSIONS[$dir]}" ]]; then local excluded_paths=(${EXCLUSIONS[$dir]}) for excluded in "${excluded_paths[@]}"; do local full_path="$dir/$excluded" local temp_path="temp_excluded/$full_path" if [[ -e "$temp_path" ]]; then echo "Restoring excluded path: $full_path" mkdir -p "$(dirname "$full_path")" rm -rf "$full_path" cp -r "$temp_path" "$(dirname "$full_path")" fi done fi } # Function to preserve root-level excluded files preserve_root_files() { if [[ -n "${EXCLUSIONS["root"]}" ]]; then local excluded_paths=(${EXCLUSIONS["root"]}) for excluded in "${excluded_paths[@]}"; do if [[ -e "$excluded" ]]; then echo "Preserving root-level excluded file: $excluded" mkdir -p "temp_excluded/root" cp -r "$excluded" "temp_excluded/root/" fi done fi } # Function to restore root-level excluded files restore_root_files() { if [[ -n "${EXCLUSIONS["root"]}" ]]; then local excluded_paths=(${EXCLUSIONS["root"]}) for excluded in "${excluded_paths[@]}"; do if [[ -e "temp_excluded/root/$excluded" ]]; then echo "Restoring root-level excluded file: $excluded" cp -r "temp_excluded/root/$excluded" "./" fi done fi } # Create temp directory for exclusions mkdir -p temp_excluded # Preserve root-level exclusions before sync preserve_root_files # Switch to dev branch git checkout dev # Sync directories for dir in "${DIRS[@]}"; do if [ ! -d "$dir" ]; then echo "Creating $dir..." mkdir -p "$dir" fi # Preserve excluded paths before sync if [[ -d "$dir" ]]; then preserve_excluded "$dir" fi echo "Syncing $dir..." git checkout "${{ env.TEMP_BRANCH }}" -- "$dir" || exit 1 # Restore excluded paths after sync restore_excluded "$dir" done # Sync files for file in "${FILES[@]}"; do dir=$(dirname "$file") if ! should_exclude "$dir" "$file"; then echo "Syncing $file..." git checkout "${{ env.TEMP_BRANCH }}" -- "$file" || true else echo "Skipping excluded file: $file" fi done # Restore root-level excluded files restore_root_files # Cleanup temp directory rm -rf temp_excluded - name: Clean up temporary branch if: always() run: git branch -D "${{ env.TEMP_BRANCH }}" || true - name: Check for changes id: check_changes run: | if [[ -n "$(git status --porcelain)" ]]; then echo "has_changes=true" >> $GITHUB_OUTPUT else echo "has_changes=false" >> $GITHUB_OUTPUT fi - name: Create Pull Request if: steps.check_changes.outputs.has_changes == 'true' uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.PAT_TOKEN }} commit-message: "chore: Sync directories and files from upstream" title: "chore: Sync directories and files from upstream" body: | Automated sync of directories and files from upstream repository. Changes included in this sync: Directories: - cmp-android (excluding src/main/res, dependencies, ic_launcher-playstore.png, google-services.json) - cmp-desktop (excluding icons) - cmp-ios (excluding iosApp/Assets.xcassets) - cmp-web (excluding src/jsMain/resources, src/wasmJsMain/resources) - cmp-shared - build-logic - fastlane - scripts - config - .github - .run Files: - Gemfile - Gemfile.lock - ci-prepush.bat - ci-prepush.sh Root-level exclusions: - secrets.env Workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} branch: sync-dirs-${{ github.run_number }} delete-branch: true labels: | sync automated pr base: dev