---
version: '3'

vars:
  COLLECTION_DEPS: collection_dependencies
  MAIN_TASKS_PATH: tasks/main.yml
  META_PATH: meta/main.yml
  MOLECULE_RESULTS_PATH: molecule/.results
  PRE_SHARED_VAULT_KEY: YTtEnhPWtftHFcP3HneVmz6vX2qMqAwobTDAbvDwrdyunAaDCQ
  REQUIREMENTS_PATH: requirements.yml
  ROLE_NAME: '{{.GALAXY_NAMESPACE}}.{{.GALAXY_ROLE_NAME}}'
  SAMPLE_PROJECT: https://github.com/megabyte-labs/ansible-snapd
  VARIABLES_PATH: .variables.json

tasks:
  build:none:
    log:
      start: Skipping build stage because Ansible project's do not require building
    cmds:
      - task: :donothing

  collection-dependencies:
    deps:
      - :install:software:jq
      - :install:software:yq
    env:
      COLLECTIONS:
        sh: jq --arg collections "$(yq eval -o=json '.collections' {{.REQUIREMENTS_PATH}})" '.{{.COLLECTION_DEPS}} = ($collections | fromjson) |
          .{{.COLLECTION_DEPS}}[] | "<a href=\"" + .source + "/" + (.name | split(".") | join("/")) + "\" title=\"" + .name +
          " collection on Ansible Galaxy\" target=\"_blank\"><img alt=\"" + .name + " Ansible Galaxy badge\"
          src=\"https://img.shields.io/badge/Ansible%20Galaxy-" + .name + "-000000?logo=ansible&logoColor=white&style=for-the-badge\"></a>"'
          -r  {{.VARIABLES_PATH}} | jq --raw-input --slurp 'split("\n") | .[0:((. | length) - 1)]'
      TMP:
        sh: mktemp
    log:
      error: Failed to generate documentation variable for collection dependencies
      start: Generating documentation variable for collection dependencies
      success: Generated documentation variable for collection dependencies
    cmds:
      - |
        jq --arg collections "$COLLECTIONS" '.{{.COLLECTION_DEPS}} = ($collections | fromjson)' '{{.VARIABLES_PATH}}' > "$TMP"
        mv "$TMP" '{{.VARIABLES_PATH}}'

  collection-dependencies:markdown:
    deps:
      - :install:software:jq
    vars:
      COLLECTION_LENGTH:
        sh: jq -r '.{{.COLLECTION_DEPS}} | length' '{{.VARIABLES_PATH}}'
      FILE_PATH: .autodoc/{{.COLLECTION_DEPS}}.md
    env:
      MULTIPLE_COLLECTION_TEXT: "### Galaxy Collections\n\nThis role is dependent on multiple Ansible Galaxy collections.
        The collections along with a links to their source are listed below.\n\n{{\"{{\"}}{{.COLLECTION_DEPS}}{{\"}}\"}}"
      SINGLE_COLLECTION_TEXT: "### Galaxy Collection\n\nThis role is dependent on the following Ansible Galaxy
        collection:\n\n{{\"{{\"}}{{.COLLECTION_DEPS}}{{\"}}\"}}"
    log:
      error: Failed to generate documentation partial for collection dependencies
      start: Generating documentation partial for collection dependencies
      success: Generated documentation partial for collection dependencies
    cmds:
      - mkdir -p '{{dir .FILE_PATH}}'
      - |
        {{if (eq .COLLECTION_LENGTH "0")}}
          echo '' > '{{.FILE_PATH}}'
        {{else if (eq .COLLECTION_LENGTH "1")}}
          echo "$SINGLE_COLLECTION_TEXT" > '{{.FILE_PATH}}'
        {{else}}
          echo "$MULTIPLE_COLLECTION_TEXT" > '{{.FILE_PATH}}'
        {{end}}
    sources:
      - '{{.FILE_PATH}}'
      - '{{.VARIABLES_PATH}}'

  galaxy:import:
    log:
      error: Error occurred while importing Ansible Galaxy role
      start: Triggering Ansible Galaxy import
      success: Successfully imported role on Ansible Galaxy
    cmds:
      - |
        GITHUB_ROLE_SLUG="$(jq -r '.blueprint.repository.github' package.json | sed 's/.*\///')"
        {{.PYTHON_HANDLE}} ansible-galaxy role import --token "$ANSIBLE_GALAXY_TOKEN" {{.GITHUB_ORG}} "$GITHUB_ROLE_SLUG"
    status:
      - '[ -z "$ANSIBLE_GALAXY_TOKEN" ]'

  galaxy:requirements:
    log:
      error: Error encountered while installing the Ansible Galaxy requirements specified in `requirements.yml`
      start: Installing the Ansible Galaxy requirements specified in `requirements.yml`
      success: Installed the Ansible Galaxy requirements specified in `requirements.yml`
    cmds:
      - |
        if [ -f ~/.netrc ]; then
          chmod 600 ~/.netrc
        fi
      - cmd: '{{.PYTHON_HANDLE}} ansible-galaxy install -r requirements.yml --ignore-errors'
        ignore_error: true
    sources:
      - requirements.yml

  init:
    cmds:
      - ansible-galaxy init --role-skeleton=/path/to/skeleton role_name

  keywords:sync:
    deps:
      - :install:npm:prettier
      - :install:software:jq
      - :install:software:yq
    summary: |
      # Sync Galaxy Tags with `package.json` Keywords

      This task syncs the Ansible Galaxy tags found in `meta/main.yml` with the keywords in the `package.json`
      file. The Ansible Galaxy tags are capped to a maximum of 20 tags.
    env:
      MERGED_TAGS:
        sh: jq -s --argjson galaxy "$(yq e -o=j '.galaxy_info.galaxy_tags' meta/main.yml)" '.[0].keywords + $galaxy | sort | unique' package.json
      MERGED_TAGS_LENGTH:
        sh: jq -s --argjson galaxy "$(yq e -o=j '.galaxy_info.galaxy_tags' meta/main.yml)" '.[0].keywords + $galaxy | sort | unique | length' package.json
    log:
      error: Error encountered while running the `package.json` / `meta/main.yml` synchronization logic
      start: Synchronizing the keywords in `package.json` and `meta/main.yml`
      success: Synchronized the keywords in `package.json` and `meta/main.yml`
    cmds:
      - |
        GALAXY_INFO="$(yq e -o=j meta/main.yml)"
        OPTIONAL_TAGS="$(jq '.keywords' .config/common-keywords.json)"
        TMP="$(mktemp)"
        RESULT="$MERGED_TAGS"
        if [ "$MERGED_TAGS_LENGTH" -gt 20 ]; then
          function updateList() {
            REMOVE_KEY="$(jq -n --argjson optional "$OPTIONAL_TAGS" '$optional['"$1"']')"
            RESULT="$(jq -n --argjson remove "$REMOVE_KEY" --argjson jq "$RESULT" '$jq | del(.[] | select(. == $remove))')"
          }
          LOOP_COUNT="$((MERGED_TAGS_LENGTH-20))"
          for i in $(seq "$LOOP_COUNT"); do
            updateList "$i"
          done
        fi
        jq -r --argjson result "$MERGED_TAGS" '.keywords = $result' package.json > "$TMP"
        mv "$TMP" package.json
        prettier --write package.json > /dev/null
        mkdir -p .cache/megabytelabs
        jq -n --argjson result "$RESULT" --argjson gi "$GALAXY_INFO" '$gi | .galaxy_info.galaxy_tags = $result' > .cache/megabytelabs/galaxy-meta.json
        yq eval -P .cache/megabytelabs/galaxy-meta.json > meta/main.yml
      - task: :fix:prettier
        vars:
          CLI_ARGS: meta/main.yml
      - task: :fix:yaml:dashes
        vars:
          CLI_ARGS: meta/main.yml

  mod-ansible-autodoc:
    todo: Add ansible-autodoc-fork to the includes of the package
    cmds:
      - |
        if [ -n "$CI" ]; then
          pip3 install ansible-autodoc-fork
        fi
      - task: mod-ansible-autodoc:generate
      - task: mod-ansible-autodoc:variables

  mod-ansible-autodoc:generate:
    deps:
      - :install:pipx:mod-ansible-autodoc
      - :install:software:jq
    env:
      ACTIONS_DESCRIPTION:
        sh: jq -r '.autodoc_actions_description' '{{.VARIABLES_PATH}}'
      # PATH:
      #   sh: echo "$PATH:$(poetry env info | grep 'Python   /' | sed 's/Python   //')"
      TAGS_DESCRIPTION:
        sh: jq -r '.autodoc_tags_description' '{{.VARIABLES_PATH}}'
      TODO_DESCRIPTION:
        sh: jq -r '.autodoc_todo_description' '{{.VARIABLES_PATH}}'
      VARIABLES_DESCRIPTION:
        sh: jq -r '.autodoc_variables_description' '{{.VARIABLES_PATH}}'
    log:
      error: Error encountered while generating documentation partials with `mod-ansible-autodoc`
      start: Compiling `mod-ansible-autodoc` documentation from comments in the play *.yml files
      success: Successfully generated documentation partials with `mod-ansible-autodoc`
    cmds:
      - >
        {{.PYTHON_HANDLE}}mod-ansible-autodoc --actions-title '## Features' --actions-description "$ACTIONS_DESCRIPTION"
        --tags-title '### Tags' --tags-description "$TAGS_DESCRIPTION" --todo-title '### TODO'
        --todo-description "$TODO_DESCRIPTION" --variables-title '## Variables' --variables-description
        "$VARIABLES_DESCRIPTION" --variable-example-comment-prefix '#💬'
      - mkdir -p .autodoc
      - mv ansible_actions.md ansible_tags.md ansible_todo.md ansible_variables.json ansible_variables.md .autodoc
    sources:
      - '{{.VARIABLES_PATH}}'
      - defaults/**/*.yml
      - tasks/**/*.yml
      - vars/**/*.yml

  mod-ansible-autodoc:variables:
    deps:
      - :install:software:jq
    log:
      error: Failed to merge `.autodoc/ansible_variables.json` into `.variables.json`
      start: Merging `.autodoc/ansible_variables.json` into `.variables.json`
      success: Successfully merged `.autodoc/ansible_variables.json` into `.variables.json`
    cmds:
      - |
        ROLE_VARIABLES="$(jq -r '.role_variables' .autodoc/ansible_variables.json)"
        TMP="$(mktemp)"
        jq --arg vars "$ROLE_VARIABLES" '.role_variables = ($vars | fromjson)' '{{.VARIABLES_PATH}}' > "$TMP"
        mv "$TMP" '{{.VARIABLES_PATH}}'

  prepare:
    deps:
      - :ci:commit:config
    log:
      error: Failed to ensure GitLab and GitHub are in sync
      start: Preparing for Ansible Galaxy upload
      success: GitLab and GitHub are in sync
    cmds:
      - task: :git:remotes
      - git pull origin master
      - git push github master

  publish:
    cmds:
      - task: galaxy:import

  quickstart:
    deps:
      - :install:software:jq
      - :symlink:{{.REPOSITORY_SUBTYPE}}
      - task: :install:python:requirements
        vars:
          INSTALL_OPTIONS: --no-dev
    cmds:
      - git reset --hard HEAD
      - |
        if ! git pull origin master; then
          git config url."https://gitlab.com/".insteadOf git@gitlab.com:
          git config url."https://github.com/".insteadOf git@github.com:
          git pull origin master || true
        fi
      - task: quickstart:environment
      - task: quickstart:map
      - task: quickstart:demo

  quickstart:cli:
    deps:
      - :install:software:openssl
    summary: |
      # Ansible Quickstart CLI

      Use this task if you already know the inventory file you would like to run the
      `main.yml` playbook on. The unique feature is that this task will first run
      `playbooks/init.yml` (and skip any task tagged with `skip_on_init`), reboot,
      and then run the normal `main.yml`. This allows you to provision a single computer
      that serves both as the client and host of Ansible (since some software requires
      reboots).

      {{.QUICKSTART_VAULT_SECURITY}}
    vars:
      INVENTORY: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}inventories/local.yml{{end}}'
      QUICKSTART_VAULT_SECURITY: |
        ## Ansible Vault Password Security

        To achieve automation wherever possible, we save your Ansible Vault password
        on disk during the installation process (i.e. to preserve the information
        inbetween reboots).

        To make it more secure, we employ the following measures:
        1. The password is forcibly removed anytime the ansible-playbook command fails
        2. It is passed in via the `ANSIBLE_VAULT_PASSWORD` variable to minimize the possibility
        of the password displaying in the terminal or getting added to the command history.
        3. It is stored in `~/.VAULT_PASSWORD` so you can easily spot it if something
        goes wrong.
    env:
      ANSIBLE_CALLBACKS_ENABLED: 'junit, ansible.posix.profile_tasks, ansible.posix.timer, sentry'
      ANSIBLE_STDOUT_CALLBACK: community.general.yaml
      ANSIBLE_VAULT_PASSWORD_FILE: ~/.VAULT_PASSWORD
      JUNIT_FAIL_ON_CHANGE: true
      JUNIT_HIDE_TASK_ARGUMENTS: true
      JUNIT_OUTPUT_DIR: .results/junit
      QUICKSTART_PLAYBOOK_MATCH: |
        # Playbook Matching Inventory File Name

        A playbook with the same file name as the selected inventory was found in the
        `playbooks/` directory. When the file names match up, this "quick start" script
        will use the matching playbook file instead of the `main.yml` playbook found in
        the root of the repository.
      QUICKSTART_VAULT_SECURITY: '{{.QUICKSTART_VAULT_SECURITY}}'
    log:
      error: Error occurred while running the Ansible play
      start: Running the Ansible play locally
      success: Successfully ran the Ansible play locally
    cmds:
      - cmd: |
          if [ ! -f "$ANSIBLE_VAULT_PASSWORD_FILE" ]; then
            .config/log info 'Adding `~/ANSIBLE_PLAYBOOK_CONTINUE.sh` to run on reboot'
            echo "#!/usr/env/bin bash" > ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
            echo "" > ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
            echo "cd $PWD" >> ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
            echo 'task ansible:quickstart:cli -- {{.INVENTORY}}' >> ~/ANSIBLE_PLAYBOOK_CONTINUE.sh
            if [ -z "$ANSIBLE_VAULT_PASSWORD" ]; then
              MD_TMP="$(mktemp)"
              echo "$QUICKSTART_VAULT_SECURITY" > "$MD_TMP"
              .config/log md "$MD_TMP"
              .config/log info 'Read about security measures above.'
              .config/log prompt 'What is your Ansible Vault password?'
              export ANSIBLE_VAULT_PASSWORD="$(.config/log password 'Enter Vault password (leave empty if there is not a password yet)..')"
            fi
          fi
          .config/log info 'Writing the `ANSIBLE_VAULT_PASSWORD` to temporary file in user home directory'
          echo "$ANSIBLE_VAULT_PASSWORD" > ~/.VAULT_PASSWORD
          INVENTORY="{{.INVENTORY}}"
          INVENTORY_SLUG="$(echo "$INVENTORY" | sed 's/inventories\/\(.*\).yml/\1/')"
          if [[ '{{.INVENTORY}}' == 'inventories/quickstart.yml' ]]; then
            if [ -f '/etc/qubes-rpc' ] && [[ "$(whoami)" == 'user' ]]; then
              .config/log info 'Assuming `ANSIBLE_USER` name to be `user` since this is Qubes'
              export ANSIBLE_USER="user"
            elif [ -z "$ANSIBLE_USER" ]; then
              WHOAMI="$(whoami)"
              .config/log prompt 'In the next step, select a user with `sudo` privileges'
              if ! .config/log confirm 'Run playbook with `'"${WHOAMI}"'`?'; then
                export ANSIBLE_USER="$(.config/log input 'Enter the username of the admin account you wish to use..')"
              else
                export ANSIBLE_USER="$WHOAMI"
              fi
            else
              .config/log info '`ANSIBLE_USER` is set to `'"$ANSIBLE_USER"'`'
            fi
            if [ -z "$ANSIBLE_PASSWORD" ]; then
              if sudo -n echo &> /dev/null; then
                .config/log info 'Assuming passwordless sudo since `sudo -n echo` was truthy'
                .config/log info 'Bypassing `ANSIBLE_PASSWORD` prompt'
              else
                .config/log prompt 'Enter the `sudo` password for your selected user (`'"$ANSIBLE_USER"'`)'
                export ANSIBLE_PASSWORD="$(.config/log password 'Enter password (or just press enter if there is none)..')"
              fi
            else
              .config/log info '`ANSIBLE_PASSWORD` is present as an environment variable.. bypassing password prompt'
            fi
            if [ -z "$MOLECULE_GROUP" ]; then
              if [ -f '/etc/qubes-rpc' ]; then
                .config/log info 'Machine is a Qubes dom0 environment'
                export MOLECULE_GROUP="qubes"
              else
                .config/log info 'Assuming machine to be macOS/Linux'
                export MOLECULE_GROUP="standard"
              fi
            fi
          fi
          if [ -f local/requirements.txt ]; then
            pip3 install -r local/requirements.txt
          else
            .config/log warn 'The `local/requirements.txt` file is missing'
          fi
          if [ -f "playbooks/${INVENTORY_SLUG}.yml" ]; then
            PLAY_TMP="$(mktemp)" && echo "$QUICKSTART_PLAYBOOK_MATCH" > "$PLAY_TMP" && .config/log md "$PLAY_TMP"
            {{.PYTHON_HANDLE}}ansible-playbook --skip-tags "dotfiles,mas" -vvv -i {{.INVENTORY}} "playbooks/${INVENTORY_SLUG}.yml" || EXIT_CODE="$?"
          else
            .config/log info 'Using the `main.yml` playbook because there is no playbook located in `'"playbooks/${INVENTORY_SLUG}.yml"'`'
            {{.PYTHON_HANDLE}}ansible-playbook --skip-tags "dotfiles,mas" -vvv -i {{.INVENTORY}} main.yml || EXIT_CODE="$?"
          fi
          #if [ -n "$EXIT_CODE" ]; then
          #  .config/log error 'There was an error while running the playbook.'
          #  .config/log warn 'Ensure there are no secrets in plain text (if you choose to upload the logs so our developers can fix this issue).'
          #  .config/log confirm 'Upload the playbook log so the developers can debug?'
          #  # sentry-cli
          #fi
        ignore_error: true
      - sleep 5
      - .config/log info 'Ensuring the temporary vault password file is forcibly removed'
      - rm -f ~/.VAULT_PASSWORD
      - rm -f ~/ANSIBLE_PLAYBOOK_CONTINUE.sh

  quickstart:demo:
    cmds:
      - task: quickstart:cli
    status:
      - '[ -f files/inventory-map.json ]'

  quickstart:environment:
    cmds:
      - task: :ansible:playbook:environment:cli
        vars:
          CLI_ARGS:
            sh: echo "$ENV"
    status:
      - '[ -z "$ENV" ]'

  quickstart:map:
    deps:
      - :install:pipx:getmac
      - :install:software:gum
      - :install:software:jq
    summary: |
      # Quickstart Mapping

      This task is a helper task that attempts to automatically select the appropriate
      Ansible inventory based on the MAC address. If the mapping entry is not already
      saved, this task will guide the user through a series of prompts.

      {{.MAC_ADDRESS_EXPLANATION}}
    vars:
      INVENTORY_OPTIONS:
        sh: echo "\""$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\//inventories\//' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"")')"\""
      INVENTORY_OPTIONS_LENGTH:
        sh: find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | length'
      MAC_ADDRESS_EXPLANATION: |
        ## Mapping MAC Addresses to Inventory Files

        In order to achieve a completely automated flow, we have the ability
        to define a map of MAC addresses and inventory files in the `files/`
        folder.

        You can get your MAC address by using the `getmac` program that this
        task installs or you can run the following on Linux:

        ```
        cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address
        ```

        On Windows, if you are provisioning with Docker (the default "Quick Start" method)
        and if you make sure you are running it on either a clean system or have no other
        Docker containers running, then the MAC address will be:

        ```
        02:42:ac:11:00:02
        ```

        If you wanted to run the Quick Start method on Windows, you could create a file in
        `files/inventory-map.json` that looks something like this:

        ```
        {
          "02:42:ac:11:00:02": "inventories/workstation.yml"
        }
        ```

        This configuration would instruct the script to automatically use the `inventories/workstation.yml`
        inventory. If your MAC address is missing, the script will open an interactive prompt and include
        the ability to save your MAC address to the file for later use.
    env:
      INVENTORY_EXPLANATION: |
        # Which Inventory Should I Use?

        A special / great starting point is the `quickstart.yml` inventory which allows you to pass your username
        and password through a prompt. It is intended to be used to provision one machine at a time from that machine.
        It is also intended to be used with the **Quick Start** links at the top of the README.md. It can be used to
        provision any of our supported operating systems.

        ## TLDR: Choose `quickstart.yml`
      MAC_ADDRESS_EXPLANATION: '{{.MAC_ADDRESS_EXPLANATION}}'
    cmds:
      - |
        PATH="$PATH:$HOME/.local/bin"
        # MAC_ADDRESS="$(cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address)" # Does not work on macOS
        MAC_ADDRESS="$(getmac)"
        TARGET_INV="$(jq --arg macAddress "$MAC_ADDRESS" -r '.[$macAddress]' files/inventory-map.json)"
        if [[ "$TARGET_INV" == '' ]]; then
          .config/log warn 'Initializing `files/inventory-map.json` since it appears to be an empty file'
          echo '{}' > files/inventory-map.json
        fi
        if [ "$TARGET_INV" != 'null' ] && [ "$TARGET_INV" != '' ]; then
          .config/log info "Provisioning with "'`'"$TARGET_INV"'`'
          task ansible:quickstart:cli -- "$TARGET_INV"
        else
          MD_TMP="$(mktemp)"
          echo "$MAC_ADDRESS_EXPLANATION" > "$MD_TMP"
          .config/log md "$MD_TMP"
          .config/log warn "MAC address missing from inventory-map.json ($MAC_ADDRESS). Details printed above."
          if [ '{{.INVENTORY_OPTIONS_LENGTH}}' != '0' ]; then
            .config/log prompt 'Given the information above, would you like to save your MAC address to the `files/inventory-map.json` file?'
            if .config/log confirm 'Save MAC address?'; then
              INV_TMP="$(mktemp)" && echo "$INVENTORY_EXPLANATION" > "$INV_TMP" && .config/log md "$INV_TMP"
              .config/log prompt 'Which inventory file would you like the associate the MAC address with?'
              INVENTORY_FILE="$(.config/log choose {{.INVENTORY_OPTIONS}})"
              TMP="$(mktemp)"
              .config/log info 'Generating new `files/inventory-map.json` file'
              jq --arg inventory "$INVENTORY_FILE" --arg macaddr "$MAC_ADDRESS" '.[$macaddr] = $inventory' files/inventory-map.json > "$TMP"
              mv "$TMP" files/inventory-map.json
              .config/log success "Successfully associated the selected inventory with this machine's MAC address (remember to git add / commit)"
              task ansible:quickstart:cli -- "$INVENTORY_FILE"
            else
              INV_TMP="$(mktemp)" && echo "$INVENTORY_EXPLANATION" > "$INV_TMP" && .config/log md "$INV_TMP"
              .config/log prompt 'Which inventory file would you like to use?'
              INVENTORY_FILE="$(.config/log choose {{.INVENTORY_OPTIONS}})"
              task ansible:quickstart:cli -- "$INVENTORY_FILE"
            fi
          else
            .config/log error 'There are no inventories defined in the `inventories/` folder.'
            .config/log info 'Try running `task environment` to link to sample environments'
            exit 1
          fi
        fi
    status:
      - '[ ! -f files/inventory-map.json ]'

  sync:requirements:
    deps:
      - :install:software:jq
      - :install:software:yq
    log:
      error: Failed to synchronize role dependencies in `{{.META_PATH}}` to `{{.REQUIREMENTS_PATH}}`
      start: Ensuring role dependencies in `{{.META_PATH}}` are also listed in `{{.REQUIREMENTS_PATH}}`
      success: Successfully ensured role dependencies in `{{.META_PATH}}` are also listed in `{{.REQUIREMENTS_PATH}}`
    cmds:
      - |
        ROLES="$(yq eval '.roles' '{{.REQUIREMENTS_PATH}}')"
        yq eval -o=json '.dependencies' '{{.META_PATH}}' | jq -rc '.[] .role' | while read ROLE_NAME; do
          if [[ ! "$ROLES" =~ "$ROLE_NAME" ]]; then
            yq eval -i -P '.roles = .roles + {"name": "'"$ROLE_NAME"'"}' '{{.REQUIREMENTS_PATH}}'
          fi
        done
      - task: :fix:yaml:dashes
        vars:
          CLI_ARGS: '{{.REQUIREMENTS_PATH}}'

  update:galaxy-id:
    log:
      error: Failed to look up or inject the Ansible Galaxy project ID into `package.json`
      start: Adding Ansible Galaxy project ID to `package.json` (if available)
      success: Successfully ensured Ansible Galaxy project ID is in `package.json` (if the project is on Ansible Galaxy)
    cmds:
      - |
        TMP="$(mktemp)"
        PROJECT_ID="$(ansible-galaxy info '{{.ROLE_NAME}}' 2> /dev/null | grep -E 'id: [0-9]' | cut -d ' ' -f2)"
        if [ "$PROJECT_ID" ]; then
          jq --arg a "$PROJECT_ID" '.blueprint.ansible_galaxy_project_id = $a' package.json > "$TMP"
          mv "$TMP" package.json
        fi
    status:
      - jq -e 'has("blueprint.ansible_galaxy_project_id")' package.json

  update:variables:
    cmds:
      - task: :ansible:ansibler:ansibler
      - task: update:variables:descriptions

  update:variables:descriptions:
    deps:
      - :install:software:jq
      - :install:software:yq
    vars:
      ALT_PREFIX: This repository is the home of an [Ansible](https://www.ansible.com/) role that
      DESCRIPTION:
        sh: yq e '.galaxy_info.description' '{{.META_PATH}}'
      DESCRIPTION_LOWER: '{{lower (trunc 1 .DESCRIPTION)}}{{substr 1 (len .DESCRIPTION) .DESCRIPTION}}'
      SUBHEADER_PREFIX: An Ansible role that
    env:
      ALT: '{{.ALT_PREFIX}} {{.DESCRIPTION_LOWER}}'
      GALAXY_INFO:
        sh: yq e -o=json '.galaxy_info' '{{.META_PATH}}'
      SUBHEADER: '{{.SUBHEADER_PREFIX}} {{.DESCRIPTION_LOWER}}'
      TMP:
        sh: mktemp
    log:
      error: Failed to inject `.variables.json` with description variables
      start: Injecting description variables into `.variables.json`
      success: Successfully updated `.variables.json` with description variables
    cmds:
      - jq -S --arg alt "$ALT" --arg galaxyinfo "$GALAXY_INFO" --arg subheader "$SUBHEADER" '.alternative_description = $alt |
        .galaxy_info = ($galaxyinfo | fromjson) | .subheader_description = $subheader' '{{.VARIABLES_PATH}}' > "$TMP"
      - mv "$TMP" '{{.VARIABLES_PATH}}'
    sources:
      - '.common/variables.{{.REPOSITORY_SUBTYPE}}.json'
      - '{{.META_PATH}}'
      - package.json
    preconditions:
      - sh: type jq > /dev/null
        msg: jq is not installed.
      - sh: type yq > /dev/null
        msg: yq is not installed.
      - sh: 'test -f "{{.META_PATH}}"'
        msg: 'The `{{.META_PATH}}` file is missing. A properly populated `{{.META_PATH}}` is required. You can find an
          example of one at {{.SAMPLE_PROJECT}}.'
      - sh: 'test -f "{{.VARIABLES_PATH}}"'
        msg: 'The `{{.VARIABLES_PATH}}` file is missing!'

  update:variables:playbook:
    cmds:
      - task: :ansible:playbook:docs

  vault:lint:file:
    summary: |
      # Check for unencrypted Ansible Vault files

      This task is leveraged by `lint-staged` to ensure that any file that matches `**/*vault.yml` is encrypted
      with Ansible Vault.
    log:
      error: '`{{.CLI_ARGS}}` is not encrypted! All files matching `**/*vault.yml` must be encrypted by `ansible-vault`.'
      start: Checking if `{{.CLI_ARGS}}` is encrypted with `ansible-vault`
      success: Ensured `{{.CLI_ARGS}}` is encrypted
    cmds:
      - |
        head -1 '{{.CLI_ARGS}}' | grep --quiet '^\$ANSIBLE_VAULT;' || {
          if [ -s '{{.CLI_ARGS}}' ]; then
            exit 1
          fi
        }

  verify:
    deps:
      - :install:software:poetry
    log:
      error: Failed to connect to Ansible Galaxy with provided token
      start: Verifying connection can be made to Ansible Galaxy
      success: Successfully connected to Ansible Galaxy
    cmds:
      - poetry update ansible
      - poetry run ansible-galaxy role setup --token "$ANSIBLE_GALAXY_TOKEN" null null null null --list