--- - name: Deploy impress-2020 from the current local version hosts: webserver vars: skip_build: no # Can override this by running `yarn deploy-skip-build` local_app_root: "{{ playbook_dir }}/../.." remote_versions_root: "/srv/impress-2020/versions" tasks: # For our deployment, our server resources are more constrained than our # dev machine, and builds are an expensive uncommon RAM & CPU spike. Let's # use our local machine for it! (I found that, running remotely, 2GB RAM # was not enough to build impress-2020 😅) - name: Run `yarn build` locally to build the current version delegate_to: localhost command: chdir: "{{ local_app_root }}" cmd: yarn build when: not skip_build - name: Generate a version name from the current timestamp command: date '+%Y-%m-%d-%s' register: new_app_version - name: Print out the new version name debug: msg: "Deploying new version: {{ new_app_version.stdout }}" - name: Save new remote folder path to a variable set_fact: remote_app_root: "{{ remote_versions_root }}/{{ new_app_version.stdout }}" - name: Create new remote folder for the new version file: path: "{{ remote_app_root }}" state: directory - name: Copy local app's source files to new remote folder ansible.posix.synchronize: src: "{{ local_app_root }}/" dest: "{{ remote_app_root }}" rsync_opts: - "--exclude=.git" - "--filter=':- .gitignore'" - name: Copy local app's .next build files to new remote folder ansible.posix.synchronize: src: "{{ local_app_root }}/.next/" dest: "{{ remote_app_root }}/.next" - name: Copy local app's .env secrets file to new remote folder ansible.posix.synchronize: src: "{{ local_app_root }}/.env" dest: "{{ remote_app_root }}/.env" - name: Check whether yarn.lock is the same as the current deployed version # First, compare the files. Then, ensure that node_modules is in a good # state and will be linkable. If this succeeds, we can do the link cheat! # If this fails, keep going, and run `yarn install` instead. command: | bash -c " cmp '{{ remote_app_root }}/yarn.lock' '/srv/impress-2020/current/yarn.lock' && realpath /srv/impress-2020/current/node_modules" failed_when: no register: can_reuse_node_modules_when_successful - name: Link node_modules to current deployed version, if they match # Linking is a pretty wild cheat to make this much faster than copying! # We're counting on the assumptions that 1) versions' dependencies don't # change after the fact, and 2) the app doesn't mutate node_modules while # running. So, these two copies of node_modules *should* just stay # permanently the way they are forever, so linking shoouulld be safe 🤞 command: | bash -c " ln -s $(realpath /srv/impress-2020/current/node_modules) {{ remote_app_root }}/node_modules" when: "can_reuse_node_modules_when_successful.rc == 0" - name: Run `yarn install` to install dependencies in new remote folder command: chdir: "{{ remote_app_root }}" cmd: yarn install when: "can_reuse_node_modules_when_successful.rc > 0" - name: Update the `current` folder to point to the new version file: src: "{{ remote_app_root }}" dest: /srv/impress-2020/current state: link - name: Reload the app in pm2 command: pm2 reload impress-2020 - name: Find older versions to clean up # Print out all but the 5 last-recently-updated versions command: chdir: "{{ remote_versions_root }}" cmd: bash -c 'ls -t | tail -n +6' register: versions_to_clean_up - name: Clean up older versions file: path: "{{ remote_versions_root }}/{{ item }}" state: absent with_items: "{{ versions_to_clean_up.stdout_lines }}"