---
version: '3'

vars:
  COLLECTION_DEPS: collection_dependencies
  MAIN_TASKS_PATH: tasks/main.yml
  META_PATH: meta/main.yml
  MOLECULE_RESULTS_PATH: molecule/.results
  REQUIREMENTS_PATH: requirements.yml
  ROLE_NAME: '{{.GALAXY_NAMESPACE}}.{{.GALAXY_ROLE_NAME}}'
  SAMPLE_PROJECT: https://github.com/ProfessorManhattan/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:
    run: once
    cmds:
      - task: galaxy:requirements:install
    sources:
      - requirements.yml
    preconditions:
      - sh: test -f requirements.yml
        msg: The requirements.yml file is missing! It should be present even if it is empty (which should almost never be the case).

  galaxy:requirements:install:
    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:
      - cmd: '{{.PYTHON_HANDLE}} ansible-galaxy install -r requirements.yml --ignore-errors'
        ignore_error: true
    status:
      - '[[ "${container:=}" == "docker" ]]'

  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
        {{.NPX_HANDLE}}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
      - '{{.NPX_HANDLE}}prettier --write meta/main.yml > /dev/null'
      - task: :fix:yaml:dashes
        vars:
          CLI_ARGS: meta/main.yml

  mod-ansible-autodoc:
    cmds:
      - task: mod-ansible-autodoc:generate
      - task: mod-ansible-autodoc:variables

  mod-ansible-autodoc:ansible-autodoc-fork:
    cmds:
      - task: :install:software:pipx
      - task: :install:python:pipx
        vars:
          PACKAGE: ansible-autodoc-fork

  mod-ansible-autodoc:generate:
    deps:
      - :install:python:requirements
      - :install:software:jq
      - mod-ansible-autodoc:ansible-autodoc-fork
    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:
    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:
      - :ansible:symlink:{{.REPOSITORY_SUBTYPE}}
      - task: :install:python:requirements
        vars:
          INSTALL_OPTIONS: --no-dev
    vars:
      INSTALLING:
        sh: if test -f install_in_progress; then echo 'true'; else echo 'false'; fi
    log:
      error: Error occurred while running the Ansible play
      start: Running the Ansible play locally
      success: Successfully ran the Ansible play locally
    cmds:
      - cp test/{{OS}}/inventory inventory
      - if [ ! -f ansible.cfg.bak ]; then cp ansible.cfg ansible.cfg.bak; fi
      - cp test/{{OS}}/ansible.cfg ansible.cfg
      - touch install_in_progress
      - |
        .config/log info 'Prompting for sudo password which is required to run the playbook'
        {{.PYTHON_HANDLE}}ansible-playbook --ask-sudo-pass{{if eq .INSTALLING 'false'}} --skip-tags "skip_on_init" playbooks/init.yml{{else}} main.yml{{end}}
      - if [ -f ansible.cfg.bak ]; then mv ansible.cfg.bak ansible.cfg; fi
      - if [ -f inventory ]; then rm inventory; fi

  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
