---
version: '3'

tasks:
  collections:download:
    cmds:
      - |
        PATH="$PATH:$HOME/.local/bin"
        ansible-galaxy collection download -r requirements.yml

  docs:
    deps:
      - docs:roles
      - docs:tags

  docs:roles:
    deps:
      - :install:software:jq
      - :install:software:yq
    log:
      error: Failed to acquire README chart data for the roles
      start: Scanning roles folder and generating chart data
      success: Finished populating roles folder chart data
    cmds:
      - |
        TMP="$(mktemp)"
        jq --arg name "Role Name" --arg description "Description" --arg github 'GitHub&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' \
        '.role_var_chart = [[$name, $description, $github]]' .variables.json > "$TMP"
        mv "$TMP" .variables.json
        for ROLE_PATH in roles/*/*; do
          if [[ "$ROLE_PATH" != *"roles/deprecated/"* ]] && [[ "$ROLE_PATH" != *"roles/cloud/"* ]] && [[ "$ROLE_PATH" != *"roles/helpers/"* ]]; then
            if [ "$(yq e '.galaxy_info.project.documentation' "${ROLE_PATH}/meta/main.yml")" != 'null' ]; then
              DOCUMENTATION_LINK="*[Documentation]($(yq e '.galaxy_info.project.documentation' "${ROLE_PATH}/meta/main.yml" | sed 's/null//'))* | "
            else
              DOCUMENTATION_LINK=""
            fi
            if [ "$(yq e '.galaxy_info.project.homepage' "${ROLE_PATH}/meta/main.yml")" != 'null' ]; then
              HOMEPAGE_LINK="*[Homepage]($(yq e '.galaxy_info.project.homepage' "${ROLE_PATH}/meta/main.yml"))* | "
            else
              HOMEPAGE_LINK=""
            fi
            GITHUB_URL="$(yq e '.galaxy_info.project.github' "${ROLE_PATH}/meta/main.yml")"
            if [ "$GITHUB_URL" == 'Not open-source' ]; then
              GITHUB_SHIELD="**❌ Closed source**"
            elif [ "$GITHUB_URL" != 'null' ]; then
              GITHUB_PATH="$(echo "$GITHUB_URL" | sed 's/https:\/\/github.com\///' | sed 's/\/$//')"
              GITHUB_OWNER="$(echo "$GITHUB_PATH" | sed 's/\/.*$//')"
              GITHUB_PROJECT_SLUG="$(echo "$GITHUB_PATH" | sed 's/^.*\///')"
              GITHUB_SHIELD="[![GitHub Repo stars](https://img.shields.io/github/stars/$GITHUB_OWNER/$GITHUB_PROJECT_SLUG?style=social)]($GITHUB_URL)"
            else
              UPSTREAM_URL="$(yq e '.galaxy_info.project.upstream' "${ROLE_PATH}/meta/main.yml")"
              if [ "$UPSTREAM_URL" != 'null' ]; then
                GITHUB_SHIELD="**[✅ Open-source]($UPSTREAM_URL)**"
              else
                GITHUB_SHIELD="*N/A*"
              fi
            fi
            SOFTWARE_NAME="$(jq -r '.blueprint.name' "${ROLE_PATH}/package.json")"
            DESCRIPTION="$(jq -r '.blueprint.overview' "${ROLE_PATH}/package.json")"
            ROLE_GITHUB_LINK="*[Role on GitHub]($(jq -r '.blueprint.repository.github' "${ROLE_PATH}/package.json"))*"
            ANSIBLE_GALAXY_NAMESPACE="$(yq e '.galaxy_info.namespace' "${ROLE_PATH}/meta/main.yml")"
            ANSIBLE_GALAXY_ROLE_NAME="$(yq e '.galaxy_info.role_name' "${ROLE_PATH}/meta/main.yml")"
            ROLE_ANSIBLE_GALAXY_URL="https://galaxy.ansible.com/${ANSIBLE_GALAXY_NAMESPACE}/${ANSIBLE_GALAXY_ROLE_NAME}"
            if [ "$ANSIBLE_GALAXY_NAMESPACE" != 'null' ] && [ "$ANSIBLE_GALAXY_ROLE_NAME" != 'null' ]; then
              URL_LINK="**[${SOFTWARE_NAME}](${ROLE_ANSIBLE_GALAXY_URL})**"
            else
              URL_LINK="**${SOFTWARE_NAME}**"
            fi
            if [ "$(jq -r '.blueprint.ansible_galaxy_project_id' "${ROLE_PATH}/package.json")" == 'null' ]; then
              ROLE_GITHUB_LINK=""
            fi
            DESCRIPTION_LINKS="(${HOMEPAGE_LINK}${DOCUMENTATION_LINK}${ROLE_GITHUB_LINK})"
            if [ "$DESCRIPTION_LINKS" != "()" ]; then
              DESCRIPTION_LINKS=" $(echo "$DESCRIPTION_LINKS" | sed 's/ | )$/)/')"
            else
              DESCRIPTION_LINKS=""
            fi
            TMP="$(mktemp)"
            jq --arg name "${URL_LINK}" --arg description "${DESCRIPTION}${DESCRIPTION_LINKS}" --arg github "${GITHUB_SHIELD}" \
            '.role_var_chart = .role_var_chart + [[$name, $description, $github]]' .variables.json > "$TMP"
            mv "$TMP" .variables.json
          fi
        done

  docs:tags:
    deps:
      - :install:npm:leasot
    summary: |
      ```shell
      # @description Processes leasot data and returns .variables.json data including charts written in @appnest/readme format
      #
      # @arg $1 The file that the leasot JSON was written to
      # @arg $2 The tag being processed
      function populateChartVar() {
        ...
      }
      ```
    vars:
      DOC_IDS: '@binaryapp,@binarycli,@brew,@cask,@chrome,@firefox,@gem,@helm,@npm,@pypi,@vscode'
    log:
      error: Failed to acquire package information from comments via `leasot`
      start: Scanning and acquiring package information in comments via `leasot`
      success: Acquired package information from comments
    cmds:
      - |
        function populateChartVar() {
          CHART='[["Package", "Description", "GitHub&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"]'
          jq --arg tag "$(echo $2 | tr '[a-z]' '[A-Z]')" -r '.[] | select(.tag == $tag) | .
          | del(. ["file", "ref", "line", "tag"]) | .text' "$1" | while read COMMENT; do
            if [ "$CHART" != '[' ]; then
              CHART="${CHART},"
            fi
            LINK="$(echo $COMMENT | sed 's/ - .*//')"
            URL_LINK="$(echo "$LINK" | sed 's/@tui //' | sed 's/@service //' | sed 's/@binary //' | sed 's/@cli //' | sed 's/@application //' | sed 's/@menubar //' | sed 's/@webapp //' | sed 's/^\[\([^)]*\)\](\([^)]*\)).*$/\[\1\](\2)/' | sed 's/ $//' | sed 's/\/$//')"
            if [[ "$LINK" == *"[GitHub](NO_GITHUB_REPOSITORY_LINK)"* ]] || [[ "$LINK" != *"https://github.com"* ]]; then
              GITHUB_SHIELD="*N/A*"
            else
              GITHUB_PATH="$(echo "$LINK" | sed 's/.*\[GitHub\](https:\/\/github.com\/\([^|]*\)).*/\1/' | \
              sed 's/.*\[.*\](https:\/\/github.com\/\([^)]*\)).*/\1/' | sed 's/\/$//')"
              GITHUB_OWNER="$(echo "$GITHUB_PATH" | sed 's/\/.*$//')"
              GITHUB_PROJECT_SLUG="$(echo "$GITHUB_PATH" | sed 's/^.*\///')"
              GITHUB_URL="https://github.com/${GITHUB_OWNER}/${GITHUB_PROJECT_SLUG}"
              GITHUB_SHIELD="[![GitHub Repo stars](https://img.shields.io/github/stars/$GITHUB_OWNER/$GITHUB_PROJECT_SLUG?style=social)]($GITHUB_URL)"
            fi
            if [[ "$LINK" == *"[Documentation]"* ]]; then
              DOCUMENTATION_LINK="*[Documentation]("$(echo "$LINK" | sed 's/.*\[Documentation\](\([^)]*\)).*/\1/')")* | "
            else
              DOCUMENTATION_LINK=""
            fi
            if [[ "$LINK" == *"[Homepage]"* ]]; then
              HOMEPAGE_LINK="*[Homepage]("$(echo "$LINK" | sed 's/.*\[Homepage\](\([^)]*\)).*/\1/' | sed 's/ $//')")* | "
            else
              HOMEPAGE_LINK=""
            fi
            if [[ "$LINK" == *"[Helm]"* ]] || [[ "$LINK" == *"[Operator]"* ]]; then
              REFERENCE_LINK="*[Helm Reference]("$(echo "$LINK" | sed 's/.*\[Helm\](\([^)]*\)).*/\1/' | sed 's/.*\[Operator\](\([^)]*\)).*/\1/')")* | "
            else
              REFERENCE_LINK=""
            fi
            DESCRIPTION_LINKS="(${HOMEPAGE_LINK}${DOCUMENTATION_LINK}${REFERENCE_LINK})"
            if [ "$DESCRIPTION_LINKS" != "()" ]; then
              DESCRIPTION_LINKS=" $(echo "$DESCRIPTION_LINKS" | sed 's/ | )$/)/')"
            else
              DESCRIPTION_LINKS=""
            fi
            DESCRIPTION="$(echo $COMMENT | sed 's/.* - //' | sed 's/\"/\\\"/g')"
            CHART="${CHART}[\"**$URL_LINK**\",\"${DESCRIPTION}${DESCRIPTION_LINKS}\",\"$GITHUB_SHIELD\"]"
          done
          CHART="${CHART}]"
          TMP_CHART="$(mktemp)"
          KEY="$(echo $2 | sed 's/^@//')"
          jq --arg chart "$CHART" --arg key "${KEY}_var_chart" '.[$key] = ($chart | fromjson)' .variables.json > "$TMP_CHART"
          mv "$TMP_CHART" .variables.json
        }
        TMP="$(mktemp)"
        leasot --tags '{{.DOC_IDS}}' --reporter json './environments/prod/group_vars/**/*.yml' > "$TMP" || true
        VARIABLES_JSON="$(jq '.' .variables.json)"
        for ID in {{replace "," " " .DOC_IDS}}; do
          populateChartVar "$TMP" "$ID"
        done

  environment:
    desc: Prompts for which environment to use and then symlinks to it
    hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-playbook"}}'
    summary: |
      # Switch environments using an interactive dialogue

      Ansible does not really provide any great ways to switch between environments (or sets of
      `host_vars/`, `group_vars/` etc.). If you place all the files and folders you wish to constitute
      as an environment inside a folder named as the name of the environment then you can use
      this task to handle the symlinking and switching between environments.

      **Example of opening the interactive prompt:**
      `task ansible:environment`

      **You can directly switch enironments to `environments/prod/` by running:**
      `task ansible:environment -- prod`
    cmds:
      - task: environment:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}

  environment:cli:
    log:
      error: Encountered an error while switching environments to `{{.CLI_ARGS}}`
      start: Switching environment to `{{.CLI_ARGS}}`
      success: Successfully switched environment to `{{.CLI_ARGS}}`
    cmds:
      - |
        {{if .CLI_ARGS}}
          for ITEM in environments/{{.CLI_ARGS}}/*; do
            ITEM="$(echo $ITEM | sed 's/.*\///')"
            if test -L "$ITEM" || ! test -e "$ITEM"; then
              rm -f "$ITEM"
              ln -s "./environments/{{.CLI_ARGS}}/$ITEM" "$ITEM"
              .config/log success "Successfully symlinked "'`'"$ITEM"'`'" from ./environments/{{.CLI_ARGS}}/$ITEM"
            else
              .config/log warn "$ITEM exists in the root and was not a symlink so it was skipped to prevent possible data loss"
            fi
          done
        {{else}}
          exit 69
        {{end}}
      - .config/log finish 'Success `environment:cli`'

  environment:prompt:
    env:
      MARKDOWN: |
        # Symlink Environment

        Answer the prompt below to switch between environments. Each environment
        should be a folder with folders and files you wish to link to from the root
        of the project. They should normally consist of a host_vars, group_vars,
        inventory, and files folder (but can contain any files/folders you wish to link).
        Each environment should have its own folder in the `environments/` folder titled
        as the name of the environment. After you select an answer, the script will
        symlink all of the items in the environments folder to the root as long as there
        is not anything except a symlink to the target location (i.e. it will overwrite
        symlinks but not files).

    cmds:
      - TMP="$(mktemp)" && echo "$MARKDOWN" > "$TMP" && .config/log md "$TMP"
      - task: environment:prompt:continue

  environment:prompt:continue:
    interactive: true
    deps:
      - :install:software:gum
      - :install:software:jq
    cmds:
      - |
        ENVIRONMENT_OPTIONS="$(find ./environments -maxdepth 1 -mindepth 1 | sed 's/\.\/environments\///' | jq -R '[.]' | jq -s -c -r 'add | join(" ")')"
        .config/log prompt 'Select an environment from the `environments/` folder to symlink to'
        ENV_OPTION="$(gum choose $(echo $ENVIRONMENT_OPTIONS))"
        task ansible:playbook:environment:cli -- "$ENV_OPTION"

  find-missing:files:
    desc: Find roles that are missing files
    hide: '{{ne (print .REPOSITORY_TYPE "-" .REPOSITORY_SUBTYPE) "ansible-playbook"}}'
    summary: |
      # Find roles that are missing any given file

      This task scans through all the folders in the roles/ directory and checks
      for the presence of a file that you pass in through the CLI.

      **Example usage:**
      `task find-missing -- logo.png`

      The example above will look through all the folders two levels deep (e.g. `./roles/tools/nmap`,
      `./roles/system/snapd`) in the roles folder and display any roles that are missing the file.
    log:
      error: Failed to scan the `/roles/*` folders for roles missing `{{.CLI_ARGS}}`
      start: Determining which roles in the `/roles/*` folders are missing `{{.CLI_ARGS}}`
      success: Finished scanning for roles missing `{{.CLI_ARGS}}` (if there are any then they should be listed above)
    cmds:
      - |
        FILES=$(find ./roles -mindepth 2 -maxdepth 2 -type d '!' -exec test -e "{}/{{.CLI_ARGS}}" ';' -print)
        .config/log info 'Found '"$(echo "$FILES" | wc -l | xargs)"' roles missing {{.CLI_ARGS}}'
        echo "$FILES"
    preconditions:
      - sh: test -d roles
        msg: The `roles/` folder is missing. Is the project set up right?

  find-missing:roles:
    summary: |
      # Find roles that are not in main.yml

      This task will collect all the role paths in the `roles/` folder and return a list
      of roles that are not present in the `main.yml` file.

      If you want to scan something other than `main.yml`, you can pass the file in as a
      CLI argument like so:

      **Example scanning file other than `main.yml`:**
      `task ansible:playbook:find-missing:roles -- playbooks/qubes.yml`
    cmds:
      - |
        TMP="$(mktemp)"
        RESULTS="$(mktemp)"
        while read ROLE; do
          ROLE_TITLE="$(echo "$ROLE" | sed 's/^.\///')"
          if ! grep "$ROLE_TITLE" '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}' > /dev/null; then
            echo "$ROLE_TITLE" >> "$RESULTS"
          fi
        done< <(find ./roles -maxdepth 2 -mindepth 2)
        if grep ".*" "$RESULTS"; then
          .config/log info 'The roles missing from `{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}` are:'
          cat "$RESULTS"
        else
          .config/log info 'All of the roles are included in `{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}main.yml{{end}}`'
        fi

  remotes:
    deps:
      - :install:software:git
      - :install:software:jq
    summary: |
      # Ensures each role is added as a remote and a sub-repo (if applicable)

      This task cycles through all the roles in the `/roles` folder and ensures
      they are added as remotes. This helps with managing the git trees used
      for combining the many role repositories into the playbook mono-repository.

      It also adds a remote for a private submodule that is intended to store
      files that are not meant to be shared. The remote is named `private`.
    run: once
    log:
      error: Failed to set remotes for one or more of the roles in the `/roles/*` folders
      start: Adding git remotes for all of the roles in the `/roles/*` folders
      success: Successfully added git remotes for all of the roles in the `/roles/*` folders
    cmds:
      - git init -q
      - |
        for ROLE_RELATIVE_PATH in roles/*/*; do
          if [ -f "${ROLE_RELATIVE_PATH}/package.json" ]; then
            ROLE_FOLDER="$(basename $ROLE_RELATIVE_PATH)"
            ROLE_HTTPS_REPO="$(jq -r '.blueprint.repository.gitlab' $ROLE_RELATIVE_PATH/package.json)"
            ROLE_SSH_REPO="$(echo $ROLE_HTTPS_REPO | sed 's/https:\/\/gitlab.com\//git@gitlab.com:/' | sed 's/$/.git/')"
            if git config "remote.${ROLE_FOLDER}.url" > /dev/null; then
              git remote set-url "$ROLE_FOLDER" "$ROLE_SSH_REPO"
            else
              git remote add "$ROLE_FOLDER" "$ROLE_SSH_REPO"
            fi
            if [ -d $ROLE_RELATIVE_PATH/.git ] && [ ! -f $ROLE_RELATIVE_PATH/.gitrepo ]; then
              task ansible:playbook:subrepo:init -- $ROLE_RELATIVE_PATH
            fi
          else
            .config/log warn "${ROLE_RELATIVE_PATH}/package.json is missing!"
          fi
        done

  run:
    cmds:
      - task: run:{{if .CLI_ARGS}}cli{{else}}prompt{{end}}

  run:cli:
    deps:
      - task: :install:python:requirements
        env:
          INSTALL_OPTIONS: --no-dev
      - :symlink:playbook
    vars:
      PLAYBOOK_MAIN:
        sh: |
          if [ -n "$PLAYBOOK_MAIN" ]; then
            echo "$PLAYBOOK_MAIN"
          else
            echo "main.yml"
          fi
    log:
      error: Error encounted while running `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
      start: Running `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
      success: Successfully ran `ansible-playbook -i inventories/{{.CLI_ARGS}} --ask-vault-pass main.yml`
    cmds:
      - |
        PATH="$PATH:$HOME/.local/bin"
        if [ -z "$ANSIBLE_VAULT_PASSWORD" ]; then
          .config/log info 'The `ANSIBLE_VAULT_PASSWORD` environment variable is not set so you will be prompted for the password'
          ansible-playbook --skip-tags "mas" -i {{.CLI_ARGS}} --ask-vault-pass "{{.PLAYBOOK_MAIN}}"
        else
          echo "$ANSIBLE_VAULT_PASSWORD" > "$HOME/.VAULT_PASSWORD"
          export ANSIBLE_VAULT_PASSWORD_FILE="$HOME/.VAULT_PASSWORD"
          .config/log info 'Bypassing Ansible Vault password prompt since the `ANSIBLE_VAULT_PASSWORD` environment variable is set'
          ansible-playbook --skip-tags "mas" -i {{.CLI_ARGS}} "{{.PLAYBOOK_MAIN}}"
        fi

  run:prompt:
    summary: '{{.MARKDOWN}}'
    vars:
      MARKDOWN: |
        # Run the Playbook

        These set of prompts will run the `main.yml` playbook after you specify:

        (1) The "environment"

        The environment is a collection of folders that should, at the very minimum,
        include "files", "group_vars", "host_vars", and "inventories". Each folder in
        the "environments" folder constitutes a different environment. By using
        environments, you can seperate different sets of variables/files or even seperate
        your private variables out into a sub-module.

        (2) An inventory file

        The Ansible inventory stored in the "inventories" folder. This will generally be
        a YML file with host connection information that also correlates the inventory with
        the proper host_vars and group_vars. It is assumed that your sudo username and
        password are encrypted inside the inventory (via "ansible-vault").
      PLAYBOOK_DESCRIPTIONS: |
        # Playbook Descriptions

        Playbooks are where you store your main logic in Ansible. The `main.yml` file in the
        root of the repository is a generic one-size-fits-all approach. You could theoretically
        store all your logic in one playbook for multiple scenarios with conditional logic but
        it might be easier to create seperate playbooks in some cases. The `main.yml` should work
        in most scenarios and is a great starting point.

        ## Alternate Playbook Descriptions

        Alternate playbooks are stored in the `playbooks/` directory. They are described below.

        *If you want their description to show up in this message, you will have to edit the appropriate
        field in `package.json`.*

    env:
      MARKDOWN: '{{.MARKDOWN}}'
    cmds:
      - |
        MD_TMP="$(mktemp)"
        echo "$MARKDOWN" > "$MD_TMP"
        .config/log md "$MD_TMP"
      - task: run:prompt:continue

  run:prompt:continue:
    interactive: true
    deps:
      - :install:software:jq
    cmds:
      - task: environment
      - echo "\"inventories"$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"inventories")')"\""
      - |
        INVENTORY_OPTIONS_LENGTH="$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\/inventories\///' | jq -R '[.]' | jq -s -c -r 'add | length')"
        if [[ "$INVENTORY_OPTIONS_LENGTH" == '0' ]]; then
          .config/log error 'There are no inventory files present in the `inventories/` folder' && exit 1
        else
          INVENTORY_OPTIONS="$(echo "\""$(find ./inventories/ -mindepth 1 -maxdepth 1 | sed 's/\.\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"")')"\"")"
          .config/log prompt 'Which inventory would you like to use?'
          CHOSEN_INVENTORY="$(.config/log choose $INVENTORY_OPTIONS)"
          export PLAYBOOK_MAIN="main.yml"
          if ! gum confirm "Would you like to use the main.yml playbook?"; then
            PLAYBOOKS_OPTIONS="$(echo "\"playbooks"$(find ./playbooks/ -mindepth 1 -maxdepth 1 -name "*.yml" | sed 's/\.\/playbooks\///' | jq -R '[.]' | jq -s -c -r 'add | join("\" \"playbooks")')"\"")"
            PLAYBOOK_DESCS_TMP="$(mktemp)" && echo "$PLAYBOOK_DESCRIPTIONS" > "$PLAYBOOK_DESCS_TMP"
            TMP_LIST="$(mktemp)"
            find ./playbooks/ -mindepth 1 -maxdepth 1 -name "*.yml" | sed 's/\.\/playbooks\///' | jq -R '[.]' | jq -s -c -r 'add' >> "$TMP_LIST"
            echo "* **main.yml:** A generic playbook that attempts to install everything" >> "$PLAYBOOK_DESCS_TMP"
            jq -c -r '.[]' "$TMP_LIST" | while read SLUG; do
              PLAYBOOK_DESC="$(jq -r '.blueprint.fileDescriptions[$file]' package.json)"
              if [ "$PLAYBOOK_DESC" != 'null' ]; then
                echo "* **playbooks/${SLUG}.yml:** $PLAYBOOK_DESC" >> "$PLAYBOOK_DESCS_TMP"
              fi
            done
            .config/log md "$PLAYBOOK_DESCS_TMP"
            .config/log prompt 'Select the playbook you would like to provision with.'
            export PLAYBOOK_MAIN="$(.config/log choose $PLAYBOOKS_OPTIONS)"
          fi
          task ansible:playbook:run:cli -- "$CHOSEN_INVENTORY"
        fi

  subrepo:init:
    deps:
      - :install:software:subrepo
    summary: |
      # Add Role as a Sub-Repository

      Since roles should each have their own repository for Ansible Galaxy and to make it easier
      for the community to download specific roles, they must be declared as sub-repositories.
      Submodules could also be used but we use sub-repos instead because they are more flexible.

      In the main playbook, if someone clones the playbook, the playbook and all the roles will download
      without any requirement to initialize submodules. At the same time, each role can be in its own
      repository. The playbook recognizes roles like this because they have a `.gitrepo` file that is only
      saved in the playbook version of the role. Users can interact with the playbook and its role
      repositories transparently without any need to understand what git subrepos are.

      Managers of roles can update the role repositories without any need to understand what git subrepos
      are. Managers of the playbook can use the tool [git-subrepo](https://github.com/ingydotnet/git-subrepo)
      to perform various actions including pulling changes from individual role repositories and
      other actions.

      Usage:
      `task ansible:playbook:subrepo:init -- path/to/folder/with.git/folder`
    cmds:
      - task: :git:commit:automated
      - |
        BASENAME="$(basename {{.CLI_ARGS}})"
        REMOTE="$(git remote get-url $BASENAME)"
        HUSKY=0 git subrepo init {{.CLI_ARGS}} -r "$REMOTE" -b master

  types:
    deps:
      - :install:npm:quicktype
    summary: |
      # Generate Types from Vaulted Files

      Automatically generate types from vaulted files.

      **Example Usage:**
      `task ansible:playbook:types -- ./environments/prod
    vars:
      TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
    cmds:
      - task: vault:decrypt
        vars:
          TARGET_DIR: '{{.TARGET_DIR}}'
      - |
        qtype() {
          local FILE_NO_EXT="$(echo "$1" | sed 's/.yml$//')"
          yq e -o=json '.' $1 | quicktype -l schema -o ${FILE_NO_EXT}.schema.json
        }
        while read FILE; do
          qtype "$FILE"
        done < <(find {{.TARGET_DIR}} -type f -name "*vault.yml")
      - task: vault:encrypt
        vars:
          TARGET_DIR: '{{.TARGET_DIR}}'

  vault:decrypt:
    vars:
      TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
    cmds:
      - find {{.TARGET_DIR}} -type f -name "*vault.yml" -printf "%h/\"%f\" " | xargs ansible-vault decrypt

  vault:encrypt:
    vars:
      TARGET_DIR: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}./environments/prod{{end}}'
    cmds:
      - find {{.TARGET_DIR}} -type f -name "*vault.yml" -printf "%h/\"%f\" " | xargs ansible-vault encrypt
