--- - name: Install basic development packages ansible.builtin.apt: name: # Development tools - git # Build tools - build-essential - python3 - python3-pip state: present become: true - name: Check if NodeSource Node.js is installed ansible.builtin.command: node --version register: node_version_check failed_when: false changed_when: false - name: Check if NodeSource repository exists and is correct ansible.builtin.shell: | if [ -f /etc/apt/sources.list.d/nodesource.list ]; then if grep -q "deb \[signed-by=/etc/apt/keyrings/nodesource.gpg\] https://deb.nodesource.com/node_22.x nodistro main" /etc/apt/sources.list.d/nodesource.list; then echo "correct_config" else echo "wrong_config" fi else echo "not_exists" fi register: nodesource_repo_check failed_when: false changed_when: false # noqa command-instead-of-module when: node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - name: Check if NodeSource GPG key exists and is correct ansible.builtin.shell: | if [ -f /etc/apt/keyrings/nodesource.gpg ]; then if file /etc/apt/keyrings/nodesource.gpg | grep -q "PGP"; then echo "correct_key" else echo "wrong_key" fi else echo "not_exists" fi register: nodesource_key_check failed_when: false changed_when: false # noqa command-instead-of-module when: node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - name: Remove incorrect NodeSource repository ansible.builtin.file: path: /etc/apt/sources.list.d/nodesource.list state: absent become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_repo_check.stdout == "wrong_config" - name: Remove incorrect NodeSource key ansible.builtin.file: path: /etc/apt/keyrings/nodesource.gpg state: absent become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_key_check.stdout == "wrong_key" - name: Create keyrings directory ansible.builtin.file: path: /etc/apt/keyrings state: directory mode: '0755' become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_key_check.stdout in ["not_exists", "wrong_key"] - name: Add NodeSource GPG key only if needed ansible.builtin.get_url: url: https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key dest: /etc/apt/keyrings/nodesource.gpg mode: '0644' force: true become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_key_check.stdout in ["not_exists", "wrong_key"] - name: Import NodeSource GPG key into apt keyring ansible.builtin.apt_key: file: /etc/apt/keyrings/nodesource.gpg state: present become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_key_check.stdout in ["not_exists", "wrong_key"] - name: Add NodeSource repository only if needed ansible.builtin.apt_repository: repo: "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" state: present update_cache: false become: true when: - node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - nodesource_repo_check.stdout in ["not_exists", "wrong_config"] - name: Install Node.js 22 from NodeSource ansible.builtin.apt: name: nodejs state: present become: true when: node_version_check.rc != 0 or not node_version_check.stdout.startswith('v22') - name: Verify Node.js installation ansible.builtin.command: node --version register: final_node_version changed_when: false - name: Display Node.js version ansible.builtin.debug: msg: "Node.js version installed: {{ final_node_version.stdout if final_node_version.stdout is defined else 'Not checked in dry-run mode' }}" # Cursor IDE installation (using AppImage) # Downloads the latest version from cursor.com API - name: Install Cursor IDE block tags: ['cursor', 'ide'] block: - name: Install libfuse2 dependency for AppImage ansible.builtin.apt: name: libfuse2 state: present update_cache: false become: true when: ansible_os_family == "Debian" - name: Check if Cursor is already installed at /usr/local/bin ansible.builtin.stat: path: /usr/local/bin/cursor register: cursor_bin_check - name: Get Cursor download URL from API and download AppImage ansible.builtin.shell: | DOWNLOAD_URL=$(curl -sL "https://www.cursor.com/api/download?platform=linux-x64&releaseTrack=stable" | grep -o '"downloadUrl":"[^"]*' | cut -d'"' -f4) wget --timeout=60 --tries=3 -O /tmp/cursor.AppImage "$DOWNLOAD_URL" args: creates: /tmp/cursor.AppImage when: not cursor_bin_check.stat.exists register: cursor_download retries: 2 delay: 5 until: cursor_download.rc == 0 - name: Make Cursor AppImage executable ansible.builtin.file: path: /tmp/cursor.AppImage mode: '0755' when: - not cursor_bin_check.stat.exists - cursor_download is defined - cursor_download.rc is defined - cursor_download.rc == 0 - name: Install Cursor to /usr/local/bin ansible.builtin.copy: src: /tmp/cursor.AppImage dest: /usr/local/bin/cursor mode: '0755' remote_src: true when: - not cursor_bin_check.stat.exists - cursor_download is defined - cursor_download.rc is defined - cursor_download.rc == 0 become: true - name: Clean up Cursor download ansible.builtin.file: path: /tmp/cursor.AppImage state: absent when: - cursor_download is defined - cursor_download.rc is defined - cursor_download.rc == 0 - name: Display Cursor installation status ansible.builtin.debug: msg: "{{ 'Cursor already installed' if cursor_bin_check.stat.exists else ('Cursor installed successfully' if (cursor_download is defined and cursor_download.rc is defined and cursor_download.rc == 0) else 'Cursor installation failed - download manually from cursor.com') }}" # Cursor extensions installation - name: Install Cursor extensions block when: - install_cursor | default(true) | bool - install_cursor_extensions | default(false) | bool - cursor_extensions is defined - cursor_extensions | length > 0 tags: ['cursor', 'extensions'] block: - name: Install Cursor extensions ansible.builtin.shell: | cursor --install-extension {{ item }} --force --user-data-dir={{ ansible_env.HOME }}/.cursor-root 2>/dev/null || true loop: "{{ cursor_extensions }}" register: cursor_ext_install changed_when: "'successfully installed' in cursor_ext_install.stdout.lower()" failed_when: false become: true become_user: "{{ ansible_user }}" - name: Display Cursor extensions status ansible.builtin.debug: msg: "Installed {{ cursor_extensions | length }} Cursor extensions"