---
version: '3'

tasks:
  all:
    deps:
      - ':{{if eq .REPOSITORY_TYPE "packer"}}packer:update:descriptions{{else}}donothing{{end}}'
      - ':{{if eq .REPOSITORY_TYPE "docker"}}docker:update:sort{{else}}donothing{{end}}'
      - files
      - :python:requirementstxt
    cmds:
      - task: all:continue

  all:continue:
    deps:
      - all:continue:remotes
      - all:docs
      - ':{{if eq .REPOSITORY_SUBTYPE "playbook"}}ansible:playbook:collections:download{{else}}donothing{{end}}'

  all:continue:remotes:
    cmds:
      - task: upstream:remotes
      - task: :git:remotes
      - task: ':{{if eq .REPOSITORY_SUBTYPE "playbook"}}ansible:playbook:remotes{{else}}donothing{{end}}'

  all:docs:
    cmds:
      - task: '{{if eq .REPOSITORY_TYPE "common"}}:donothing{{else}}{{if eq .REPOSITORY_TYPE "documentation"}}:donothing{{else}}all:docs:generate{{end}}{{end}}'

  all:docs:generate:
    deps:
      - contributing
      - readme

  ansible:
    deps:
      - :ansible:populate:dependencies
      - :ansible:populate:meta
      - :ansible:update:galaxy-id

  contributing:
    deps:
      - :install:npm:prettier
      - :install:npm:readme
    vars:
      CONTRIB_TEMPLATE:
        sh: |
          if [ -f ".config/docs/blueprint-contributing-{{.REPOSITORY_SUBTYPE}}.md" ]; then
            echo ".config/docs/blueprint-contributing-{{.REPOSITORY_SUBTYPE}}.md"
          else
            echo ".config/docs/blueprint-contributing.md"
          fi
    log:
      error: Encountered error while generating `docs/CONTRIBUTING.md`
      start: Generating `docs/CONTRIBUTING.md` using document partials
      success: Successfully generated `docs/CONTRIBUTING.md`
    cmds:
      - mkdir -p docs
      - >
        readme generate --silent --headingPrefix '{}' --config .variables.json
        --input "{{.CONTRIB_TEMPLATE}}" --output docs/CONTRIBUTING.md
      - task: markdown:scrub
        vars:
          SCRUB_FILE: docs/CONTRIBUTING.md
      - prettier --write docs/CONTRIBUTING.md > /dev/null
    sources:
      - docs/CONTRIBUTING.md
      - .config/docs/**/*
      - .variables.json
    preconditions:
      - sh: test -f .variables.json
        msg: The `.variables.json` file is not present.
      - sh: type readme > /dev/null
        msg: '`@appnest/readme` is not installed globally.'

  files:
    deps:
      - files:ansible:keywords:sync
      - files:dockerignore
      - files:docs
      - files:go:dummy
      - files:husky
      - files:initctl
    log:
      error: Encountered error while updating miscellaneous files
      start: Updating miscellaneous files
      success: Updated miscellaneous files

  files:ansible:keywords:sync:
    cmds:
      - task: :{{if eq .REPOSITORY_SUBTYPE "role"}}ansible:keywords:sync{{else}}donothing{{end}}

  files:dockerignore:
    cmds:
      - |
        if [ -f .dockerignore ]; then
          TMP="$(mktemp)"
          echo '# To keep changes, only add items to end of file' > "$TMP"
          cat .gitignore >> "$TMP"
          if [ ! -f .config/dockerignore ]; then
            curl -sSL https://gitlab.com/megabyte-labs/common/shared/-/raw/master/common/.config/dockerignore > .config/dockerignore
          fi
          cat .config/dockerignore >> "$TMP"
          echo '# Saved entries below' >> "$TMP"
          cat .dockerignore | sed -n '/# Saved entries below/,$p' | sed 's/# Saved entries below//' | awk 'NF' >> "$TMP"
          mv "$TMP" .dockerignore
        elif [ '{{.PROJECT_TYPE}}' == 'project' ]; then
          if [ -f .config/dockerignore ]; then
            rm .config/dockerignore
          fi
        fi

  files:docs:
    cmds:
      - mkdir -p docs/partials && echo '<!-- Add content in this file to include it in automatically generated README.md -->' > docs/partials/guide.md
    status:
      - '[ -f docs/partials/guide.md ]'

  files:go:dummy:
    cmds:
      - echo -e 'package main\n\nfunc main() {\n}\n' > .config/dummy.go
    status:
      - '[ "{{.REPOSITORY_SUBTYPE}}" != "cli" ] || [ "{{.REPOSITORY_TYPE}}" == "go" ]'

  files:husky:
    vars:
      CONTAINER:
        sh: if [ "{{.DOCKER_ENVIRONMENT}}" == "true" ]; then echo "docker"; fi
    cmds:
      - task: :common:{{if eq .CONTAINER "docker"}}husky:ci{{else}}husky{{end}}

  files:initctl:
    cmds:
      - |
        if [ -f initctl ] && [ -f .config/initctl ]; then
          cp .config/initctl initctl
          .config/log info 'Ensured that the `initctl` polyfill file is synchronized with the upstream version'
        fi

  finish:
    cmds:
      - cmd: git push
        ignore_error: true
      - task: :ci:synchronize

  init:
    log:
      error: Encountered error while initializing project
      start: Ensuring project is initialized
    cmds:
      - |
        if ! test -f package.json; then
          echo '{"blueprint": {}}' > package.json
        fi
    status:
      - test -f package.json

  man-page:
    deps:
      - :install:modules:local
      - :install:npm:remark
      - :install:npm:prettier
      - :install:npm:readme
    vars:
      MAN_TEMPLATE: '{{.REPOSITORY_SUBTYPE}}-blueprint-man.md'
    cmds:
      - |
        if test -f ".config/docs/{{.MAN_TEMPLATE}}"; then
          readme generate --headingPrefix '{}' --silent --config .variables.json --input ".config/docs/{{.MAN_TEMPLATE}}" --output MAN.md
          prettier --write MAN.md > /dev/null
          .config/log info 'Generated MAN.md'
          mkdir -p dist
          remark --use man MAN.md --output dist/man
          .config/log success 'Converted MAN.md to man page located in `dist/man`'
          rm MAN.md
        fi
    sources:
      - .config/docs/**/*
      - .variables.json
      - dist/man
    preconditions:
      - sh: test -f .variables.json
        msg: The `.variables.json` file is not present.

  markdown:scrub:
    vars:
      DIVIDER_SRC: <a href="\1" style="width:100%"><img style="width:100%"
        src="https://gitlab.com/megabyte-labs/assets/-/raw/master/png/aqua-divider.png" /></a>
      REGEX: .*https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/.*.png)][(]\(.*\)[)].*$
    cmds:
      - task: markdown:scrub:{{OS}}
        vars:
          DIVIDER_SRC: '{{.DIVIDER_SRC}}'
          REGEX: '{{.REGEX}}'
          SCRUB_FILE: '{{.SCRUB_FILE}}'

  markdown:scrub:darwin: /usr/bin/sed -i .bak 's^{{.REGEX}}^{{.DIVIDER_SRC}}^g' {{.SCRUB_FILE}} && rm {{.SCRUB_FILE}}.bak

  markdown:scrub:linux: sed -i 's^{{.REGEX}}^{{.DIVIDER_SRC}}^g' {{.SCRUB_FILE}}

  modules:
    deps:
      - :install:software:git
    summary: |
      # Ensure all submodules in `.modules/` are updated

      Some of our projects include submodules. These submodules are generally
      stored in the `.modules/` folder in the root of the project. Some projects
      might symlink files to one of the submodules stored in the `.modules/` folder.
      If you are ok with the risk, you can use this task to update all the submodules
      to the latest on the remote's master branch.
    log:
      error: Failed to ensure submodules in the `.modules/` folder are up-to-date
      start: Ensuring submodules in the `.modules/` folder are up-to-date
      success: Successfully ensured submodules in the `.modules/` folder are up-to-date
    cmds:
      - git submodule update --init --recursive
      - |
        ROOT_DIR="$PWD"
        if ls .modules/*/ > /dev/null 2>&1; then
          for SUBMODULE_PATH in .modules/*/; do
            cd $SUBMODULE_PATH
            DEFAULT_BRANCH=$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)
            git reset --hard HEAD
            git checkout "$DEFAULT_BRANCH"
            git pull origin "$DEFAULT_BRANCH" --ff-only || true
            cd "$ROOT_DIR"
          done
          .config/log success 'Ensured submodules in the `.modules` folder are pointing to the master branch'
        fi
    status:
      - '! ls .modules/*/ > /dev/null 2>&1'

  project:
    log:
      start: Pulling `master` if `origin` is defined
    cmds:
      - |
        if [ -d .git ] && git branch -r | grep origin > /dev/null; then
          git pull origin master --no-rebase || true
        fi

  readme:
    deps:
      - ':{{if eq .REPOSITORY_TYPE "ansible"}}ansible:collection-dependencies:markdown{{else}}donothing{{end}}'
      - ':{{if eq .REPOSITORY_SUBTYPE "role"}}ansible:mod-ansible-autodoc{{else}}donothing{{end}}'
      - :install:npm:prettier
      - :install:npm:readme
    vars:
      README_TEMPLATE: blueprint-readme-{{.REPOSITORY_SUBTYPE}}.md
    log:
      error: Error encountered while generating `README.md`
      start: Generating `README.md`
      success: Generated README.md successfully
    cmds:
      - >
        readme generate --headingPrefix '{}' --silent --config .variables.json
        --input ".config/docs/{{.README_TEMPLATE}}"
      - task: markdown:scrub
        vars:
          SCRUB_FILE: README.md
      - task: ':{{if eq .REPOSITORY_TYPE "packer"}}packer:update:readme{{else}}donothing{{end}}'
      - prettier --write README.md > /dev/null
    sources:
      - .autodoc/*
      - .config/docs/**/*
      - .variables.json
      - README.md
    preconditions:
      - sh: 'test -f .config/docs/{{.README_TEMPLATE}}'
        msg: 'The README.md template file is not present at `.config/docs/{{.README_TEMPLATE}}`.'
      - sh: test -f .variables.json
        msg: The `.variables.json` file is not present.

  repositories:
    cmds:
      - task: modules
      - task: project

  start:
    deps:
      - :common:requirements
      - variables

  update:
    deps:
      - ':{{if eq .REPOSITORY_SUBTYPE "role"}}common:update:ansible{{else}}donothing{{end}}'
      - ':{{if eq .REPOSITORY_TYPE "packer"}}{{if eq .REPOSITORY_SUBTYPE "server"}}packer:latestos{{else}}donothing{{end}}{{else}}donothing{{end}}'
      - init
      - repositories
    summary: |
      # Refresh project with latest upstream code and ensure project files are up-to-date

      This task will pull the latest upstream code and overwrite any files that are out of date.
      Ideally, you should run this task often to ensure there are no merge conflicts and to
      ensure you are using the latest production settings. This task is also run by CI so
      normally if you pull the latest changes, you should already have the updates that this
      task applies.

      **Example usage:**
      `task update`
    run: once
    cmds:
      - task: start
      - task: all
      - |
        if [ -f Dockerfile ]; then
          task {{if eq .REPOSITORY_TYPE "docker"}}docker:update:labels{{else}}donothing{{end}}
        fi

  upstream:remotes:
    deps:
      - :install:software:jq
    log:
      error: Error adding upstream git remotes
      start: Ensuring upstream git remotes are added (if applicable)
      success: Successfully added upstream git remotes
    cmds:
      - |
        COUNT="$(jq -r '.blueprint.upstreamRemotes | length' package.json)"
        for i in $(seq $COUNT); do
          REMOTE="$(jq -r --arg count "$(("$i" - 1))" '.blueprint.upstreamRemotes[($count | tonumber)].remote' package.json)"
          URL="$(jq -r --arg count "$(("$i" - 1))" '.blueprint.upstreamRemotes[($count | tonumber)].url' package.json)"
          if [ "$REMOTE" != 'null' ] && [ "$URL" != 'null' ]; then
            if git remote | grep "$REMOTE"; then
              git remote remove $REMOTE
            fi
            git remote add $REMOTE $URL
          else
            .config/log warn '`blueprint.upstreamRemotes` objects should have the `remote`, `url`, and `branch` keys'
          fi
        done
    status:
      - '[ "$(jq -r ".blueprint.upstreamRemotes | length" package.json)" == "0" ]'

  upstream:remotes:pull:
    deps:
      - :install:software:jq
    log:
      error: Error pulling latest from upstream remotes
      start: Pulling latest changes from upstream remotes
      success: Successfully pulled latest changes from upstream remotes
    cmds:
      - |
        COUNT="$(jq -r '.blueprint.upstreamRemotes | length' package.json)"
        for i in $(seq $COUNT); do
          REMOTE="$(jq -r --arg count "$(("$i" - 1))" '.blueprint.upstreamRemotes[($count | tonumber)].remote' package.json)"
          URL="$(jq -r --arg count "$(("$i" - 1))" '.blueprint.upstreamRemotes[($count | tonumber)].url' package.json)"
          BRANCH="$(jq -r --arg count "$(("$i" - 1))" '.blueprint.upstreamRemotes[($count | tonumber)].branch' package.json)"
          if [ "$REMOTE" != 'null' ] && [ "$URL" != 'null' ] && [ "$BRANCH" != 'null' ]; then
            if git remote | grep "$REMOTE"; then
              git remote remove $REMOTE
            fi
            git remote add $REMOTE $URL
            git pull $REMOTE $BRANCH
          else
            .config/log warn '`blueprint.upstreamRemotes` objects must have the `remote`, `url`, and `branch` keys'
          fi
        done

  variables:
    deps:
      - :install:software:jq
    cmds:
      - task: :upstream:variables
        vars:
          INPUT_FILE: .config/variables.json
          OUTPUT_FILE: .variables.json
      - task: ':{{if eq .REPOSITORY_TYPE "go"}}{{if eq .REPOSITORY_SUBTYPE "cli"}}go:help{{else}}donothing{{end}}{{else}}donothing{{end}}'
      - task: ':{{if eq .REPOSITORY_TYPE "packer"}}packer:update:variables{{else}}donothing{{end}}'
      - task: ':{{if eq .REPOSITORY_TYPE "ansible"}}ansible:update:variables{{if eq .REPOSITORY_SUBTYPE "playbook"}}:playbook{{end}}{{else}}donothing{{end}}'
      - task: ':{{if eq .REPOSITORY_SUBTYPE "tap"}}install:tap:scan{{else}}donothing{{end}}'
      - task: ':{{if eq .REPOSITORY_SUBTYPE "scoop"}}install:scoop:scan{{else}}donothing{{end}}'
