--- # Deploy Application Code via Git or Rsync - name: Set git_repo_url from provided value or default ansible.builtin.set_fact: git_repo_url: "{{ application_git_repository_url if (application_git_repository_url is defined and application_git_repository_url != '') else application_git_repository_url_default }}" - name: Determine deployment method ansible.builtin.set_fact: deployment_method: "{{ application_deployment_method | default('git') }}" when: application_deployment_method is not defined - name: Ensure Git is installed (for Git deployment) ansible.builtin.apt: name: git state: present update_cache: no become: yes when: deployment_method == 'git' - name: Ensure application code directory exists ansible.builtin.file: path: "{{ application_code_dest }}" state: directory owner: "{{ ansible_user }}" group: "{{ ansible_user }}" mode: '0755' become: yes # Git Deployment Tasks - name: Check if repository already exists (Git) ansible.builtin.stat: path: "{{ application_code_dest }}/.git" register: git_repo_exists when: deployment_method == 'git' - name: Check if destination directory exists (Git) ansible.builtin.stat: path: "{{ application_code_dest }}" register: dest_dir_exists when: deployment_method == 'git' - name: Remove destination directory if it exists but is not a git repo (Git) ansible.builtin.file: path: "{{ application_code_dest }}" state: absent when: - deployment_method == 'git' - dest_dir_exists.stat.exists - not git_repo_exists.stat.exists become: yes - name: Clone repository (if not exists) (Git) ansible.builtin.git: repo: "{{ git_repo_url }}" dest: "{{ application_code_dest }}" version: "{{ application_git_branch }}" force: no update: no when: - deployment_method == 'git' - not git_repo_exists.stat.exists environment: GIT_TERMINAL_PROMPT: "0" vars: ansible_become: no register: git_clone_result retries: "{{ application_git_retries | default(5) }}" delay: "{{ application_git_retry_delay | default(10) }}" until: git_clone_result is succeeded ignore_errors: yes - name: Fail if git clone failed after retries (Git) ansible.builtin.fail: msg: "Failed to clone repository after {{ application_git_retries | default(5) }} retries. Gitea may be unreachable or overloaded. Last error: {{ git_clone_result.msg | default('Unknown error') }}" when: - deployment_method == 'git' - not git_repo_exists.stat.exists - git_clone_result is failed - name: Check if repository is already on correct branch (Git) ansible.builtin.shell: | cd {{ application_code_dest }} CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") TARGET_BRANCH="{{ application_git_branch | default('main') }}" if [ "$CURRENT_BRANCH" = "$TARGET_BRANCH" ] || [ "$CURRENT_BRANCH" = "HEAD" ]; then echo "ALREADY_ON_BRANCH" else echo "NEEDS_UPDATE" fi register: git_branch_check changed_when: false failed_when: false when: - deployment_method == 'git' - git_repo_exists.stat.exists - application_skip_git_update | default(false) | bool == false - name: Update repository (if exists and not already on correct branch) (Git) ansible.builtin.git: repo: "{{ git_repo_url }}" dest: "{{ application_code_dest }}" version: "{{ application_git_branch }}" force: yes update: yes when: - deployment_method == 'git' - git_repo_exists.stat.exists - application_skip_git_update | default(false) | bool == false - git_branch_check.stdout | default('NEEDS_UPDATE') == 'NEEDS_UPDATE' environment: GIT_TERMINAL_PROMPT: "0" vars: ansible_become: no register: git_update_result retries: "{{ application_git_retries | default(5) }}" delay: "{{ application_git_retry_delay | default(10) }}" until: git_update_result is succeeded ignore_errors: yes - name: Skip git update (repository already on correct branch or skip flag set) ansible.builtin.debug: msg: "Skipping git update - repository already on correct branch or skip_git_update is set" when: - deployment_method == 'git' - git_repo_exists.stat.exists - (application_skip_git_update | default(false) | bool == true) or (git_branch_check.stdout | default('NEEDS_UPDATE') == 'ALREADY_ON_BRANCH') - name: Fail if git update failed after retries (Git) ansible.builtin.fail: msg: "Failed to update repository after {{ application_git_retries | default(5) }} retries. Gitea may be unreachable or overloaded. Last error: {{ git_update_result.msg | default('Unknown error') }}" when: - deployment_method == 'git' - git_repo_exists.stat.exists - application_skip_git_update | default(false) | bool == false - git_branch_check.stdout | default('NEEDS_UPDATE') == 'NEEDS_UPDATE' - git_update_result is defined - git_update_result is failed - name: Set ownership of repository files (Git) ansible.builtin.file: path: "{{ application_code_dest }}" owner: "{{ ansible_user }}" group: "{{ ansible_user }}" recurse: yes become: yes when: deployment_method == 'git' # Rsync Deployment Tasks - name: Clear destination directory before sync (Rsync) ansible.builtin.shell: | # Remove all files and directories except .git (if it exists) find {{ application_code_dest }} -mindepth 1 -maxdepth 1 -not -name '.git' -exec rm -rf {} + 2>/dev/null || true become: yes changed_when: true failed_when: false register: clear_result when: deployment_method == 'rsync' - name: Display clear status (Rsync) ansible.builtin.debug: msg: "Cleared destination directory before sync (preserved .git if present)" when: - deployment_method == 'rsync' - clear_result.rc | default(0) == 0 - application_show_status | default(true) | bool - name: Synchronize application code from repository root (Rsync) ansible.builtin.synchronize: src: "{{ application_rsync_source }}/" dest: "{{ application_code_dest }}/" delete: no recursive: yes rsync_opts: "{{ application_rsync_opts | default(['--chmod=D755,F644', '--exclude=.git', '--exclude=.gitignore', '--exclude=node_modules', '--exclude=vendor', '--exclude=.env', '--exclude=.env.*', '--exclude=*.log', '--exclude=.idea', '--exclude=.vscode', '--exclude=.DS_Store', '--exclude=*.swp', '--exclude=*.swo', '--exclude=*~', '--exclude=.phpunit.result.cache', '--exclude=coverage', '--exclude=.phpunit.cache', '--exclude=public/assets', '--exclude=storage/logs', '--exclude=storage/framework/cache', '--exclude=storage/framework/sessions', '--exclude=storage/framework/views', '--exclude=deployment', '--exclude=docker', '--exclude=.deployment-archive-*', '--exclude=docs', '--exclude=tests']) }}" when: deployment_method == 'rsync' delegate_to: localhost run_once: true - name: Ensure executable permissions on PHP scripts (Rsync) ansible.builtin.file: path: "{{ application_code_dest }}/{{ item }}" mode: '0755' loop: "{{ application_php_scripts | default(['worker.php', 'console.php']) }}" when: - deployment_method == 'rsync' - item is defined ignore_errors: yes - name: Verify critical files exist (Rsync) ansible.builtin.stat: path: "{{ application_code_dest }}/{{ item }}" register: critical_files_check loop: "{{ application_critical_files | default(['worker.php', 'console.php', 'composer.json']) }}" when: deployment_method == 'rsync' - name: Display file verification results (Rsync) ansible.builtin.debug: msg: | File Verification: {% for result in critical_files_check.results | default([]) %} - {{ result.item }}: {{ 'EXISTS' if result.stat.exists else 'MISSING' }} {% endfor %} when: - deployment_method == 'rsync' - application_show_status | default(true) | bool - critical_files_check is defined - name: Fail if critical files are missing (Rsync) ansible.builtin.fail: msg: | Critical files are missing after sync: {% for result in critical_files_check.results | default([]) %} {% if not result.stat.exists %}- {{ result.item }}{% endif %} {% endfor %} when: - deployment_method == 'rsync' - critical_files_check is defined - critical_files_check.results | selectattr('stat.exists', 'equalto', false) | list | length > 0 - name: Display deployment summary ansible.builtin.debug: msg: | ======================================== Application Code Deployment Summary ======================================== Method: {{ deployment_method | upper }} Destination: {{ application_code_dest }} {% if deployment_method == 'git' %} Repository: {{ git_repo_url }} Branch: {{ application_git_branch }} {% elif deployment_method == 'rsync' %} Source: {{ application_rsync_source }} {% endif %} ======================================== when: application_show_status | default(true) | bool