Sync runner checkout / sync (pull_request) Successful in 7s
Explicit deploys with empty host_apps used to skip Django and still refresh web-static, which looked like a static-only deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
3.2 KiB
YAML
80 lines
3.2 KiB
YAML
---
|
|
# Generic app deployment.
|
|
#
|
|
# CI passes: app=<name> app_env=<beta|prod> app_ref=<git sha>
|
|
# Manual run with none of those redeploys every app in this host's host_apps
|
|
# at branch master.
|
|
#
|
|
# host_apps (host_vars) lists what runs on THIS host; app_catalog (group_vars)
|
|
# describes how each app is built.
|
|
|
|
- name: Classify catalog by type
|
|
ansible.builtin.set_fact:
|
|
django_names: "{{ app_catalog | dict2items | selectattr('value.type', 'equalto', 'django') | map(attribute='key') | list }}"
|
|
node_names: "{{ app_catalog | dict2items | selectattr('value.type', 'equalto', 'node-static') | map(attribute='key') | list }}"
|
|
|
|
- name: Resolve deploy targets for {{ inventory_hostname }}
|
|
ansible.builtin.set_fact:
|
|
deploy_targets: >-
|
|
{{ (host_apps | default([]) | selectattr('name', 'equalto', app | default('')) | selectattr('env', 'equalto', app_env | default('')) | list)
|
|
if (app is defined and app_env is defined)
|
|
else (host_apps | default([])) }}
|
|
|
|
- name: Show deploy targets
|
|
ansible.builtin.debug:
|
|
msg: "ref={{ app_ref | default('(per-app default branch)') }} targets={{ deploy_targets | map(attribute='name') | zip(deploy_targets | map(attribute='env')) | list }}"
|
|
|
|
# Explicit --app/--env with no host_apps match used to silently no-op Django
|
|
# and still refresh web-static (looked like a "static-only" deploy). Fail loud.
|
|
- name: Fail when requested app+env is not on this host
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
No host_apps entry for app={{ app }} env={{ app_env }} on
|
|
{{ inventory_hostname }}. Check inventory/host_vars and app_catalog
|
|
(django apps need type: django + compose_file). Catalog keys:
|
|
{{ app_catalog.keys() | list }}.
|
|
when:
|
|
- app is defined
|
|
- app_env is defined
|
|
- deploy_targets | length == 0
|
|
|
|
- name: Fail when requested app missing from app_catalog
|
|
ansible.builtin.fail:
|
|
msg: >-
|
|
app={{ app }} is not in app_catalog. Add it with type: django (docker)
|
|
or type: node-static. Known: {{ app_catalog.keys() | list }}.
|
|
when:
|
|
- app is defined
|
|
- app not in app_catalog
|
|
|
|
- name: Deploy Django (docker compose) apps
|
|
ansible.builtin.include_tasks: django.yml
|
|
loop: "{{ deploy_targets | selectattr('name', 'in', django_names) | list }}"
|
|
loop_control:
|
|
loop_var: app_item
|
|
label: "{{ app_item.name }}/{{ app_item.env }}"
|
|
|
|
- name: Run Django migrations once (shared external DB)
|
|
ansible.builtin.command:
|
|
cmd: >-
|
|
docker compose -f {{ app_catalog[item.name].compose_file }} --env-file .env
|
|
exec -T {{ app_catalog[item.name].web_service }}
|
|
{{ app_catalog[item.name].migrate_cmd }}
|
|
chdir: "{{ apps_src_dir }}/{{ item.name }}_{{ item.env }}"
|
|
environment:
|
|
COMPOSE_PROJECT_NAME: "{{ item.name }}_{{ item.env }}"
|
|
loop: "{{ deploy_targets | selectattr('name', 'in', django_names) | list }}"
|
|
loop_control:
|
|
label: "{{ item.name }}/{{ item.env }}"
|
|
become: true
|
|
become_user: "{{ admin_user }}"
|
|
run_once: true
|
|
changed_when: true
|
|
|
|
- name: Deploy node static apps
|
|
ansible.builtin.include_tasks: node_static.yml
|
|
loop: "{{ deploy_targets | selectattr('name', 'in', node_names) | list }}"
|
|
loop_control:
|
|
loop_var: app_item
|
|
label: "{{ app_item.name }}/{{ app_item.env }}"
|