---
version: '3'

vars:
  PRETTIERIGNORE_CONFIG: .config/prettierignore
  SHELLCHECK_EXCLUDE: SC1091

tasks:
  all:
    deps:
      - eslint
      - misc
      - '{{if .REPOSITORY_TYPE eq "packer"}}packer{{else}}:donothing{{end}}'
      - '{{if .REPOSITORY_TYPE eq "python"}}python{{else}}:donothing{{end}}'
      - toml
      - xml
    log:
      start: Running all stable fixers in parallel
    cmds:
      - task: yaml:dashes

  eslint:
    deps:
      - :install:modules:local
      - :install:npm:eslint
    desc: Fix JavaScript/TypeScript errors automatically
    hide: '{{not (has .REPOSITORY_TYPE (list "angular" "npm"))}}'
    summary: |
      # Fix JavaScript/TypeScript Errors with ESLint

      This task is an [`eslint`](https://eslint.org/) task. It will attempt to automatically fix
      `eslint` issues. It will report any issues it was unable to fix. The configuration found in
      `package.json` includes logic for fixing/linting TypeScript, JavaScript, JSON, TOML, and YAML.

      **Example using `eslint` to fix a single JS/TS file:**
      `task fix:js -- single.ts`

      **Example fixing all JS/TS files in a project:**
      `task fix:js`
    log:
      error: ESLint found some issues that need to be fixed manually
      start: Auto-fixing with ESLint
      success: ESLint fixing appears to have corrected all the issues {{if .CLI_ARGS}}in `{{.CLI_ARGS}}`{{else}}in the project{{end}}
    cmds:
      - '{{.NPX_HANDLE}}eslint -c package.json --no-eslintrc --format pretty --cache --cache-location .cache/eslintcache
        --fix {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}'

  go:
    desc: Fix Go with all available Go fixers
    summary: |
      # Auto-Fix Go Files

      This task will attempt to auto-fix Go files with the following auto-fixers:

      * [go]()

      If you would like to skip auto-fixing on the whole project and instead auto-fix an
      individual file, then you can do so by passing the file path as a CLI
      parameter like so:

      **Example auto-fixing an individual file:**
      `task fix:go -- path/filename.go`
    cmds:
      - task: go:fmt

  go:fmt:
    deps:
      - :install:software:go
    summary: |
      # Auto-Fix Go Files with `gofmt`

      Running this task will auto-format the Go code in the project with `gofmt`.
      In addition to writing the files (via the `-w` flag), it also attempts to
      simplify the files (via the `-s` flag).

      By default, this task will format the entire project. However, you can target
      specific files by passing the path of the `.go` file as a CLI argument.

      **Example formatting specific file:**
      `task fix:go:fmt -- path/to/file.go`
    cmds:
      - gofmt -s -w {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}

  js:
    cmds:
      - task: eslint

  json:
    deps:
      - :install:modules:local
      - :install:npm:eslint
    desc: Format and sort JSON
    summary: |
      # Automatically Alphabetize and Format JSON

      This task will format and organize JSON files based on the configuration stored in
      `.eslintrc.cjs`.

      **Example sorting a single JSON file:**
      `task fix:json -- single.json`

      **Example looping through project:**
      `task fix:json`
    log:
      error: '{{if .CLI_ARGS}}Manual fixing is still required for `{{.CLI_ARGS}}`{{else}}Failed to fix all project JSON issues with ESLint{{end}}'
      start: Linting JSON with ESLint
      success: ESLint has fixed all of the JSON issues {{if .CLI_ARGS}}in `{{.CLI_ARGS}}`{{else}}in the project{{end}}
    cmds:
      - '{{.NPX_HANDLE}}eslint -c package.json --no-eslintrc --cache --cache-location .cache/eslintcache --fix
        --format pretty --ext .json {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}'

  misc:
    deps:
      - :install:python:requirements
    summary: |
      # Miscellaneous fixes

      This task allows you to loop through the files in the project and apply miscellaneous
      fixes. You can also specify a single file. The fixes applied are:

      1. Remove UTF-8 BOM
      2. Ensure line endings are LF

      **Example applying fixes to all files:**
      `task fix:misc`

      **Example applying fixes to single file:**
      `task fix:misc -- singlefile.js`
    log:
      error: Encountered an error while performing miscellaneous fixes{{if .CLI_ARGS}} on `{{.CLI_ARGS}}`{{end}}
      start: Performing miscellaneous fixes such as removing BOM and ensuring LF line endings
      success: Finished performing miscellaneous fixes{{if .CLI_ARGS}} on `{{.CLI_ARGS}}`{{end}}
    cmds:
      - |
        function misc() {
          {{.PYTHON_HANDLE}}fix-byte-order-marker "$1"
          {{.PYTHON_HANDLE}}mixed-line-ending --fix=lf "$1"
        }
        {{if .CLI_ARGS}}
          misc '{{.CLI_ARGS}}'
        {{else}}
          while read PATHH; do
            misc "$PATHH"
          done < <(find . -type d \( {{.IGNORE_FOLDERS}} \) -prune -o -type f)
        {{end}}

  packer:
    deps:
      - :install:software:packer
    desc: Automatically fix and format Packer templates
    hide: '{{ne .REPOSITORY_TYPE "packer"}}'
    summary: |
      # Automatically fix and format Packer templates

      Packer has the ability to fix old templates that are using outdated methods. This task
      loops through all the files in the root of this repository that end with `template.json`.
      For each template, the task runs `packer fix`.

      **Example applying fixes to all files matching `*template.json`:**
      `task fix:packer`

      **Example applying fixes to single file:**
      `task fix:packer -- mytemplate.json`

      For more information on `packer fix`, see [Packer's website](https://www.packer.io/docs/commands/fix).
    log:
      start: Attempting to fix Packer template{{if .CLI_ARGS}}{{else}}s{{end}}
      stop: Error running `packer fix`
      success: Successfully ran `packer fix` on the template(s)
    cmds:
      - |
        function packerFix() {
          TMP="$(mktemp)"
          packer fix "$1" > "$TMP"
          mv "$TMP" "$1"
          .config/log success "Successfully ran `packer fix` on $1"
        }
        {{if .CLI_ARGS}}
          packerFix '{{.CLI_ARGS}}'
        {{else}}
          for TEMPLATE in *template.json; do
            packerFix "$TEMPLATE"
          done
        {{end}}

  php:
    desc: Fix PHP with all available PHP auto-fixers
    summary: |
      # Auto-Fix PHP Files

      This task will attempt to auto-fix PHP files with the following auto-fixers:

      * [go]()

      If you would like to skip auto-fixing on the whole project and instead auto-fix an
      individual file, then you can do so by passing the file path as a CLI
      parameter like so:

      **Example auto-fixing an individual file:**
      `task fix:php -- path/filename.php`
    cmds:
      - task: :donothing

  prettier:
    deps:
      - :install:modules:local
      - :install:npm:prettier
    desc: Automatically format most files using Prettier
    summary: |
      # Automatically Format Files Using Prettier

      This task will run Prettier on the project. Prettier will automatically fix formatting
      mistakes like inconsistent indent lengths, trailing spaces, and more. It will use the
      configuration specified in the `package.json` file under the `prettier` key.

      If this command is incompatible with a file then you can add the file to the `.prettierignore`
      file.

      **Example of bulk fixing:**
      `task fix:formatting`

      **Example of fixing a single file**
      `task fix:formatting -- path/filename.ext`

      For more information, see [Prettier's website](https://prettier.io/).
    log:
      start: Running Prettier on {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}}
    cmds:
      - '{{.NPX_HANDLE}}prettier --ignore-path {{.PRETTIERIGNORE_CONFIG}} --write {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}'

  python:
    deps:
      - :install:python:requirements
    desc: Automatically format Python files using Black
    hide: '{{ne .REPOSITORY_TYPE "python"}}'
    summary: |
      # Automatically Format Python Files with Black

      Black is the defacto standard when it comes to autoformatting Python files. This task will
      automatically format files that end with the `.py` extension. It ignores `.py` files that are
      in any of the locations specified in the `IGNORED_FOLDERS` variable in `Taskfile.yml`.

      **Example applying fixes to all Python files:**
      `task fix:python`

      **Example applying fixes to single Python file:**
      `task fix:python -- myfile.py`

      For more information, see [Black's GitHub page](https://github.com/psf/black).
    log:
      error: Error while running `black` auto-fixer
      start: Fixing Python with `black`
      success: Fixed {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}} with `black`
    cmds:
      - |
        {{if .CLI_ARGS}}
          {{.PYTHON_HANDLE}}black {{.CLI_ARGS}}
        {{else}}
          while read PATHH; do
            {{.PYTHON_HANDLE}}black "$PATHH"
          done < <(find . -type d \( {{.IGNORE_FOLDERS}} \) -prune -o -type f \( -name '*.py' \))
        {{end}}

  shell:
    cmds:
      - task: shellcheck
      - task: prettier

  shellcheck:
    deps:
      - :install:npm:shellcheck
    desc: Automatically apply fixes to `.sh` and `.sh.j2` files using Shellcheck
    summary: |
      # Automatically apply fixes to shell scripts using Shellcheck

      Shellcheck is generally used to lint shell scripts. This task uses Shellcheck and `git apply`
      to automatically apply Shellcheck's recommendations. It only runs on files that are not in the
      `IGNORED_FOLDERS` variable in `Taskfile.yml`.

      This task is experimental. It may work to get rid of the Shellcheck lin.config/log errors but the code
      should still be tested since it might break things. Ideally, you should apply Shellcheck's
      recommendations manually.

      **To see what changes Shellcheck will make to a file named `test.sh`, for example, you can run:**
      `npx shellcheck -f diff test.sh`

      **Example applying fixes to all shell scripts:**
      `task fix:scripts`

      **Example applying fixes to a single shell script:**
      `task fix:scripts -- myfile.sh`

      For more information, see [Shellcheck's GitHub page](https://github.com/koalaman/shellcheck).
    log:
      error: Encountered an error while linting with `shellcheck` on {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}}
      start: Running `shellcheck` auto-fixer
      success: Autofixed {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}} with `shellcheck`
    cmds:
      - |
        .config/log warn 'This is an experimental fix method - please manually inspect and test the scripts'
        {{if .CLI_ARGS}}
          {{.NPX_HANDLE}}shellcheck -e {{.SHELLCHECK_EXCLUDE}} -f diff {{.CLI_ARGS}} | git apply
        {{else}}
          find . -type d \( {{.IGNORE_FOLDERS}} \) -prune -o -type f \( -name '*.sh' -o -name '*.sh.j2' \) \
            -print0 | xargs -0 {{.NPX_HANDLE}}shellcheck -e {{.SHELLCHECK_EXCLUDE}} -f diff | git apply
        {{end}}

  xml:
    deps:
      - :install:npm:eslint
    summary: |
      # Autofix XML files

      This task will automatically apply updates to XML files. It uses Prettier and the Prettier plugin
      named `@prettier/plugin-xml` for auto-formatting.

      **Example fixing all `.xml` files:**
      `task fix:xml`

      **Example fixing specific `.xml` file(s):**
      `task fix:xml -- 'file_name.xml'`
    log:
      error: Errors were reported by ESLint when auto-fixing XML
      start: Attempting to auto-fix any XML files with ESLint
      success: Any XML files present in the project were successfully fixed/validated by ESLint
    cmds:
      - '{{.NPX_HANDLE}}eslint -c package.json --no-eslintrc --cache --cache-location .cache/eslintcache --fix
        --format pretty --ext .xml {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}'

  yaml:
    desc: Auto-format and sort YML files
    summary: |
      # Auto-Format and Sort YML files

      This task will automatically apply updates to YML files. It currently performs the following
      tasks:

      1. Ensures the first line of the file is `---`
      2. Sorts the file according to the layout specified by `.eslintrc.cjs`

      **Example usage:**
      `task fix:yaml`

      **Example fixing single file:**
      `task fix:yaml -- filename.yml`
    cmds:
      - task: yaml:dashes
      - task: yaml:order

  yaml:dashes:
    summary: |
      # Ensures YML files start with a "---"

      This task will add a `---` as the first line of YML files if it is missing. It only works
      on one YML file at a time. This task is intended to be used with lint-staged (with settings)
      normally found in the `package.json` file. You must specify the path/filename to the YML
      file you wish to fix with this task. If the file does not exist or if the file does not end
      with `.yml` or `yaml` then an error will be reported.

      This task is mainly intended to be used with `lint-staged`.

      **Example usage:**
      `task fix:yaml:dashes`

      **Example usage for one specific file:**
      `task fix:yaml:dashes -- path/filename.yml`
    log:
      error: Error encountered while ensuring YML dashes
      start: Ensuring {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}} has YML files that start with `---`
      success: Successfully ensured {{if .CLI_ARGS}}`{{.CLI_ARGS}}`{{else}}project{{end}} has YML files that start with `---`
    cmds:
      - |
        function yamlDashes() {
          if test -f "$1" && [[ "`head -c 14 "$1"`" != '$ANSIBLE_VAULT' ]] && [[ "`head -c 3 "$1"`" != '---' ]]; then
            TMP=$(mktemp)
            echo '---' | cat - "$1" > "$TMP"
            mv "$TMP" "$1"
          fi
        }
        {{if .CLI_ARGS}}
          yamlDashes '{{.CLI_ARGS}}'
        {{else}}
          while read YML_FILE; do
            yamlDashes "$YML_FILE"
          done < <(find . -type d \( {{.IGNORE_FOLDERS}} \) -prune -o -type f \( -name '*.yml' -o -name '*.yaml' \))
        {{end}}

  yaml:order:
    deps:
      - :install:modules:local
      - :install:npm:eslint
    summary: |
      # Ensure YML files are sorted properly

      This task will sort YML keys alphabetically and also obey the order specified in `.eslintrc.cjs`.
      It uses [ESLint](https://eslint.org/) along with the [`eslint-plugin-yml`](https://ota-meshi.github.io/eslint-plugin-yml/)
      plugin.

      By default, the plugin will automatically fix all YML files but you can also pass in a single file or glob
      that needs to be fixed.

      **Example fixing all `.yml` files:**
      `task fix:yaml:order`

      **Example fixing specific `.yml` file(s):**
      `task fix:yaml:order -- 'file_name.{yml,yaml}'`
    log:
      error: There are still some errors. Try running the command again.
      start: Ensuring YML file(s) are in order specified in configuration
      success: Successfully ensured YML file order
    cmds:
      - '{{.NPX_HANDLE}}eslint -c package.json --no-eslintrc --format pretty --fix --cache
        --cache-location .cache/eslintcache --ext yml,yaml {{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}.{{end}}'
