# #
#   @type               github workflow
#   @author             Aetherinox
#   @url                https://github.com/Aetherinox
#   @usage              publishes a new release on Github
#
#   @secrets            secrets.SELF_TOKEN                                          self github personal access token (fine-grained)
#                       secrets.SELF_TOKEN_CL                                       self github personal access token (classic)
#                       secrets.NPM_TOKEN                                           self npmjs access token
#                       secrets.PYPI_API_TOKEN                                      self Pypi API token (production site) - https://pypi.org/
#                       secrets.PYPI_API_TEST_TOKEN                                 self Pypi API token (test site) - https://test.pypi.org/
#                       secrets.SELF_DOCKERHUB_TOKEN                                self Dockerhub token
#                       secrets.ORG_BINARYNINJA_TOKEN                               org github personal access token (fine-grained)
#                       secrets.ORG_BINARYNINJA_TOKEN_CL                            org github personal access token (classic)
#                       secrets.ORG_BINARYNINJA_DOCKERHUB_TOKEN                     org dockerhub secret
#                       secrets.ORG_BINARYNINJA_GITEA_TOKEN                         org gitea personal access token (classic) with package:write permission
#                       secrets.BINARYSERV_GPG_KEY_ASC                              bot gpg private key (armored) | BEGIN PGP PRIVATE KEY BLOCK
#                       secrets.BINARYSERV_GPG_PASSPHRASE                           bot gpg private key passphrase
#                       secrets.DISCORD_WEBHOOK_CHAN_GITHUB_TVAPP2_RELEASES         discord webhook to report release notifications from github to discord
#                       secrets.DISCORD_WEBHOOK_CHAN_GITHUB_TVAPP2_WORKFLOWS        discord webhook to report workflow notifications from github to discord
#                       secrets.DISCORD_WEBHOOK_CHAN_GITHUB_TVAPP2_UPDATES          discord webhook to report activity notifications from github to discord
#
#   @local              these workflows can be tested locally through the use of `act`
#                           https://github.com/nektos/act
#                       Extract act to folder
#                       Add system env var with path to act.exe
#                       Run the commands:
#                           git pull https://github.com/username/repo
#                           act -W .github/workflows/labels-create.yml -P ubuntu-latest=catthehacker/ubuntu:full-22.04
#                           act -W .github/workflows/labels-create.yml -s TOKEN_CL=XXXXXXXXXX --pull=false
# #

name: '📦 Release › Github'
run-name: '📦 Release › Github'

# #
#   Triggers
# #

on:
    workflow_dispatch:
        inputs:

            # #
            #   Name of the plugin to use when creating the release zip filename
            #     e.g: tvapp2-v1.0.0.zip
            # #

            PROJECT_NAME:
                description:        '📦 Name of App'
                required:           true
                default:            'tvapp2'
                type:               string

            # #
            #   ENABLE:   the changelog generated in releases tab will only display single commits.
            #   DISABLE:  the changelog shows pull requests completed based on their labels
            # #

            CHANGELOG_MODE_COMMIT:
                description:        '📑 Use Commits Instead of PRs'
                required:           true
                default:            true
                type:               boolean

            # #
            #   ENABLE:   Will show all types of commits, including uncategorized
            #   DISABLE:  WIll only show actions that have been categorized using the format
            #                type(scope): description
            #                type: description
            # #

            SHOW_UNCATEGORIZED:
                description:        '🗂️ Show Uncategorized Commits'
                required:           true
                default:            false
                type:               boolean

            # #
            #   true            released version will be marked as a development build and will have the v1.x.x-development tag instead of -latest
            #   false           release version will be marked with -latest docker tag
            # #

            RC_RELEASE:
                description:        '🧪 Build RC (Pre-release)'
                required:           true
                default:            false
                type:               boolean

            # #
            #   only needed if env variable `RC_ONLY` = true
            #   sets the version number for the release candidate
            #       e.g: noxenv-v1.0.0-rc.1
            # #

            RC_VERSION:
                description:        '🧪 RC (Pre-release) Ver (tvapp2-rc.v1)'
                required:           false
                type:               string
                default:            '1'

# #
#   environment variables
# #

env:
    PROJECT_NAME:                   ${{ github.event.inputs.PROJECT_NAME || 'tvapp2' }}
    CHANGELOG_MODE_COMMIT:          ${{ github.event.inputs.CHANGELOG_MODE_COMMIT || true }}
    SHOW_UNCATEGORIZED:             ${{ github.event.inputs.SHOW_UNCATEGORIZED || false }}
    RC_RELEASE:                     ${{ github.event.inputs.RC_RELEASE || false }}
    RC_VERSION:                     ${{ github.event.inputs.RC_VERSION || '1' }}
    ASSIGN_USER:                    Aetherinox
    BOT_NAME_1:                     EuropaServ
    BOT_NAME_2:                     BinaryServ
    BOT_NAME_DEPENDABOT:            dependabot[bot]
    BOT_NAME_RENOVATE:              renovate[bot]
    GPG_KEY_BASE64:                 ${{ secrets.ADMINSERV_GPG_KEY_B64 }}
    GPG_KEY_PASSPHRASE:             ${{ secrets.ADMINSERV_GPG_PASSPHRASE }}

# #
#   Jobs
# #

jobs:

    # #
    #   Jobs › Initialize
    # #

    job-initialize:
        name: >-
          📦 Initialize
        runs-on: ubuntu-latest
        outputs:
            package_version: ${{ steps.task_initialize_package_getversion.outputs.PACKAGE_VERSION }}
        permissions:
            contents: write
            packages: write
        steps:

            # #
            #   Initialize › Start
            # #

            - name: '✅ Start'
              id: task_initialize_start
              run: |
                  echo "Starting build"

            # #
            #   Initialize › Set Env Variables
            # #

            - name: >-
                🕛 Get Timestamp
              id: task_initialize_label_set_timestamp
              run: |
                  echo "NOW=$(date +'%m-%d-%Y %H:%M:%S')" >> $GITHUB_ENV
                  echo "NOW_SHORT=$(date +'%m-%d-%Y')" >> $GITHUB_ENV
                  echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV
                  echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV

            # #
            #   Initialize › Checkout
            # #

            - name: '☑️ Checkout'
              id: task_initialize_checkout
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0

            # #
            #   Initialize › Set › Package.json › Version
            # #

            - name: '👁️‍🗨️ Package Version › Set'
              id: task_initialize_package_getversion
              working-directory: ./tvapp2
              run: |
                  VER=$(cat package.json | jq -r '.version')
                  echo "PACKAGE_VERSION=$VER" >> $GITHUB_OUTPUT

            # #
            #   Initialize › Get › Package.json › Version
            # #

            - name: '👁️‍🗨️ Package Version › Get'
              id: task_initialize_package_version_get
              run: |
                  echo "VERSION: ${{ steps.task_initialize_package_getversion.outputs.PACKAGE_VERSION }}"

    # #
    #   Job › Release › Github
    # #

    job-release:
        name: >-
          📦 Publish › Release
        runs-on: ubuntu-latest
        needs: [ job-initialize ]
        env:
            PACKAGE_VERSION: ${{ needs.job-initialize.outputs.package_version }}
        outputs:
            guid: ${{ steps.task_release_dotenv_get.outputs.GUID }}
            uuid: ${{ steps.task_release_dotenv_get.outputs.UUID }}
        permissions:
            contents: write
            packages: write
        steps:

            # #
            #   Release › Set Env Variables
            # #

            - name: >-
                🕛 Get Timestamp
              id: task_release_label_set_timestamp
              run: |
                  echo "YEAR=$(date +'%Y')" >> $GITHUB_ENV
                  echo "NOW=$(date +'%m-%d-%Y %H:%M:%S')" >> $GITHUB_ENV
                  echo "NOW_SHORT=$(date +'%m-%d-%Y')" >> $GITHUB_ENV
                  echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV
                  echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV

            # #
            #   Release › Checkout
            # #

            - name: '☑️ Checkout'
              id: task_release_checkout
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0

            # #
            #   Release › Start
            # #

            - name: >-
                ✅ Start
              id: task_release_start
              run: |
                echo "―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――"
                echo " Starting Documentation Build script"
                echo " Runner .............. ${{ runner.name }}"
                echo " Workflow ............ ${{ github.workflow }} (#${{ github.workflow_ref }})"
                echo " Run Number .......... #${{ github.run_number }}"
                echo " Run ID .............. https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
                echo " Triggered By ........ ${{ github.actor }}"
                echo " Time ................ ${{ env.NOW_LONG }}"
                echo "―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――"

            # #
            #   Release › Print Version Debug
            # #

            - name: '🪪 Test Next Job Version'
              id: task_release_debug_print_ver
              run: |
                  echo "VERSION: ${{ env.PACKAGE_VERSION }}"

            # #
            #   Release › Install package via NPM
            # #

            - name: '🪪 NPM › Install & Lint'
              id: task_release_npm_install
              working-directory: ./tvapp2
              run: |
                  npm ci
                  npm run lint
              env:
                  NODE_AUTH_TOKEN: ${{ secrets.SELF_TOKEN_CL }}

            # #
            #   Release › Execute npm generate so that a uuid and guid can be created
            # #

            - name: '🪪 Generate IDs'
              id: task_release_npm_env_generate
              working-directory: ./tvapp2
              run: |
                  npm run root:generate

            # #
            #   Release › .ENV › Get
            #   Get guid and uuid from env variable generated by npm
            # #

            - name: '🪪 .ENV › Get'
              id: task_release_dotenv_get
              uses: falti/dotenv-action@v1
              with:
                  path: "./tvapp2/.env"

            # #
            #   Release › .ENV › Print (Debug)
            #   Show guid and uuid from env variable generated by npm
            # #

            - name: '🪪 .ENV › Read'
              id: task_dotenv_debug_print
              run: |
                  echo "GUID: ${{ steps.task_release_dotenv_get.outputs.GUID }}"
                  echo "UUID: ${{ steps.task_release_dotenv_get.outputs.UUID }}"

            # #
            #   Release › Build › Stable
            # #

            - name: '🔨 Build › Stable › ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip'
              id: task_release_build_st
              if: |
                  startsWith( inputs.RC_RELEASE, false ) ||
                  startsWith( env.RC_RELEASE, false )
              run: |
                  echo Building STABLE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
                  zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE

                  echo Building STABLE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip
                  zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip docker-compose.yml README.md LICENSE
              env:
                  NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}

            # #
            #   Release › Build › Release Candidate
            # #

            - name: '🔨 Build › Release Candidate › ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip'
              id: task_release_build_rc
              if: |
                  startsWith( inputs.RC_RELEASE, true ) ||
                  startsWith( env.RC_RELEASE, true )
              run: |
                  echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
                  zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE

                  echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip
                  zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip docker-compose.yml README.md LICENSE
              env:
                  NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}

            # #
            #   Release › Tag › Pre Create
            #
            #   in order to use the changelog github action, you must pre-create the tag otherwise
            #   the changelog action will have no idea what tag you are going to be creating and
            #   the list of commits will not be for the correct release.
            # #

            - name: '🔖 Tag › Pre Create ${{ env.PACKAGE_VERSION }}'
              id: task_release_tag_create
              uses: rickstaa/action-create-tag@v1
              with:
                  tag: ${{ env.PACKAGE_VERSION }}
                  tag_exists_error: false
                  message: "Latest release"
                  gpg_private_key: ${{ secrets.ADMINSERV_GPG_KEY_ASC }}
                  gpg_passphrase: ${{ secrets.ADMINSERV_GPG_PASSPHRASE }}

            # #
            #   Release › Tag › Confirm
            #
            #   check if tag already exists
            # #

            - name: '🔖 Tag › Confirm ${{ env.PACKAGE_VERSION }}'
              id: task_release_tag_get
              run: |
                  echo "Tag already present: ${{ env.TAG_EXISTS }}"
                  echo "Tag already present: ${{ steps.task_release_tag_create.outputs.tag_exists }}"

            # #
            #   Release › GPG › Import Key (No Passphrase)
            #
            #   requires your GPG private key, converted to base64 binary .gpg (not armored .asc)
            # #

            - name: '🪪 GPG › Import Signing Key › W/o Passphrase'
              id: task_release_gpg_import_nopass
              if: env.GPG_KEY_BASE64 != '' && env.GPG_KEY_PASSPHRASE == ''
              run: |
                  echo $GPG_KEY_BASE64 | base64 -di | gpg --import

            # #
            #   Release › GPG › Import Key (With Passphrase)
            #
            #   requires your GPG private key, converted to base64 binary .gpg (not armored .asc)
            # #

            - name: '🪪 GPG › Import Signing Key › w/ Passphrase'
              id: task_release_gpg_import_withpass
              if: env.GPG_KEY_BASE64 != '' && env.GPG_KEY_PASSPHRASE != ''
              run: |
                  echo "$GPG_KEY_BASE64" | base64 -di > /tmp/signing-key.gpg
                  echo "$GPG_KEY_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg
                  (echo "$GPG_KEY_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1)

            # #
            #   Release › Checksum › Stable
            # #

            - name: '🆔 Checksum › Stable'
              id: task_release_checksum_st_set
              if: |
                  startsWith( inputs.RC_RELEASE, false ) ||
                  startsWith( env.RC_RELEASE, false )
              run: |
                  filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip"

                  #  get sha1 and sha256 for .zip and .gz files
                  find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha1sum | gpg --digest-algo sha256 --clearsign > sha1sum.txt.asc
                  find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha256sum | gpg --digest-algo sha256 --clearsign > sha256sum.txt.asc

                  #  get sha1sum; assign to variable
                  sha1sum="$(shasum --algorithm 1 ${filename_zip} | awk '{ print $1 }')"
                  echo "SHA1SUM=${sha1sum}" >> $GITHUB_ENV

                  #  get sha256sum; assign to variable
                  sha256sum="$(shasum --algorithm 256 ${filename_zip} | awk '{ print $1 }')"
                  echo "SHA256SUM=${sha256sum}" >> $GITHUB_ENV

                  #  no longer needed, replaced by find . command
                  #  shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt
                  echo "FILE_ZIP=${filename_zip}" >> $GITHUB_ENV

                  filename_compose_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip"
                  sha256sum_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
                  echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV

            # #
            #   Release › Checksum › Release Candidate
            # #

            - name: '🆔 Checksum › Release Candidate'
              id: task_release_checksum_rc_set
              if: |
                  startsWith( inputs.RC_RELEASE, true ) ||
                  startsWith( env.RC_RELEASE, true )
              run: |
                  filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip"

                  #  get sha1 and sha256 for .zip and .gz files
                  find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha1sum | gpg --digest-algo sha256 --clearsign > sha1sum.txt.asc
                  find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha256sum | gpg --digest-algo sha256 --clearsign > sha256sum.txt.asc

                  #  get sha1sum; assign to variable
                  sha1sum="$(shasum --algorithm 1 ${filename_zip} | awk '{ print $1 }')"
                  echo "SHA1SUM=${sha1sum}" >> $GITHUB_ENV

                  #  get sha256sum; assign to variable
                  sha256sum="$(shasum --algorithm 256 ${filename_zip} | awk '{ print $1 }')"
                  echo "SHA256SUM=${sha256sum}" >> $GITHUB_ENV

                  #  no longer needed, replaced by find . command
                  #  shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt
                  echo "FILE_ZIP=${filename_zip}" >> $GITHUB_ENV

                  filename_compose_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip"
                  sha256_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
                  echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV

            # #
            #   Release › Checksum › Print
            # #

            - name: '🆔 Checksum › Print'
              id: task_release_checksum_st_get
              run: |
                  echo "${{ env.SHA256SUM }}"

            # #
            #   Release › Contributor Images
            # #

            - name: '🥸 Contributors › Generate'
              id: task_release_contribs_generate
              uses: jaywcjlove/github-action-contributors@main
              with:
                  filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\])
                  output: CONTRIBUTORS.svg
                  avatarSize: 42

            # #
            #   Release › Changelog › Generate Tags
            #
            #   generates a changelog from the github api. requires a PREVIOUS_TAG in order to figure
            #   out the changes made between the two versions.
            #
            #   outputs:
            #     ${{ steps.changelog.outputs.changelog }}
            # #

            - name: '📝 Changelog › Pre Setup (Categorized Commits)'
              id: task_release_changelog_categorized_sha_set
              run: |
                  echo "TAG_LAST=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV
                  echo "COMMIT_LAST=$(git rev-parse HEAD)" >> $GITHUB_ENV

            # #
            #   Release › Changelog › Build (Categorized)
            #
            #   generates a changelog from the github api. requires a TAG_LAST in order to figure
            #   out the changes made between the two versions.
            #
            #   outputs:
            #       ${{ steps.task_release_changelog_categorized.outputs.changelog }}
            # #

            - name: '📝 Changelog › Build (Categorized)'
              id: task_release_changelog_categorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, false ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, false )
              uses: mikepenz/release-changelog-builder-action@v5
              with:
                  token: ${{ secrets.ADMINSERV_TOKEN }}
                  #fromTag: "${{ env.TAG_LAST }}"
                  #toTag: "${{ github.ref }}"
                  configuration: ".github/changelog-configuration.json"
                  ignorePreReleases: false
                  commitMode: ${{ inputs.CHANGELOG_MODE_COMMIT || env.CHANGELOG_MODE_COMMIT }}
                  fetchReleaseInformation: true
                  fetchViaCommits: true
                  configurationJson: |
                    {
                      "template": "## Release Info \n| Item | Value |\n| --- | --- |\n|<sub>📄 ${{ env.FILE_ZIP }}</sub>|<sub>Contains TVApp2 node source code and Docker build kit</sub>|\n|<sub>📄 ${{ env.FILE_COMPOSE_ZIP }}</sub>|<sub>Contains `docker-compose.yml`</sub>|\n|<sub>🏷️ SHA256</sub>|<sub>`${{ env.SHA256SUM }}`</sub>|\n|<sub>🏷️ GUID</sub>|<sub>`${{ steps.task_release_dotenv_get.outputs.GUID }}`</sub>|\n|<sub>🏷️ UUID</sub>|<sub>`${{ steps.task_release_dotenv_get.outputs.UUID }}`</sub>|\n|<sub>🕟 Stamp</sub>|<sub>`#{{FROM_TAG}}-#{{FROM_TAG_DATE}} 🔺 #{{TO_TAG}}-#{{TO_TAG_DATE}}`</sub>|\n|<sub>📅 Last Release</sub>|<sub>`#{{DAYS_SINCE}} days ago`</sub>|\n\n<br>\n\n---\n\n<br>\n\n### What's New\nThis release contains the following changes:\n\n<br>\n\n---\n\n<br>\n\n### Statistics\nHow the files have changed:\n<ul><li><a href='#{{RELEASE_DIFF}}'>Changed files</a> : <b>#{{CHANGED_FILES}}</b></li><li>Changes : <b>#{{CHANGES}}</b></li><li>Commits : <b>#{{COMMITS}}</b></li><li>Additions : <b>#{{ADDITIONS}}</b></li><li>Deletions : <b>#{{DELETIONS}}</b></li><li>PRs (categorized) : <b>#{{CATEGORIZED_COUNT}}</b></li><li>PRs (uncategorized) : <b>#{{UNCATEGORIZED_COUNT}}</b></li><li>PRs (open) : <b>#{{OPEN_COUNT}}</b></li>\n<br />\n</ul>\n\n<br>\n\n---\n\n<br>\n\n### Pull Requests\nThis release is associated with the following pull requests:\n#{{CHANGELOG}}\n\n<br>\n\n---\n\n<br>\n\n"
                    }
              env:
                  GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN }}

            # #
            #   Release › Changelog › Build (Uncategorized)
            #
            #   generates a changelog from the github api. requires a TAG_LAST in order to figure
            #   out the changes made between the two versions.
            #
            #   outputs:
            #       ${{ steps.task_release_changelog_categorized.outputs.changelog }}
            #
            #   shows only categorized commits using the commit standards
            #                type(scope): description
            #                type: description
            # #

            - name: '📝 Changelog › Build (Uncategorized)'
              id: task_release_changelog_uncategorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, true ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, true )
              uses: mikepenz/release-changelog-builder-action@v5
              with:
                  token: ${{ secrets.ADMINSERV_TOKEN }}
                  #fromTag: "${{ env.TAG_LAST }}"
                  #toTag: "${{ github.ref }}"
                  configuration: ".github/changelog-configuration.json"
                  ignorePreReleases: false
                  commitMode: ${{ inputs.CHANGELOG_MODE_COMMIT || env.CHANGELOG_MODE_COMMIT }}
                  fetchReleaseInformation: true
                  fetchViaCommits: true
                  configurationJson: |
                    {
                      "template": "## Release Info \n| Item | Value |\n| --- | --- |\n|<sub>📄 ${{ env.FILE_ZIP }}</sub>|<sub>Contains TVApp2 node source code and Docker build kit</sub>|\n|<sub>📄 ${{ env.FILE_COMPOSE_ZIP }}</sub>|<sub>Contains `docker-compose.yml`</sub>|\n|<sub>🏷️ SHA256</sub>|<sub>`${{ env.SHA256SUM }}`</sub>|\n|<sub>🏷️ GUID</sub>|<sub>`${{ steps.task_release_dotenv_get.outputs.GUID }}`</sub>|\n|<sub>🏷️ UUID</sub>|<sub>`${{ steps.task_release_dotenv_get.outputs.UUID }}`</sub>|\n|<sub>🕟 Stamp</sub>|<sub>`#{{FROM_TAG}}-#{{FROM_TAG_DATE}} 🔺 #{{TO_TAG}}-#{{TO_TAG_DATE}}`</sub>|\n|<sub>📅 Last Release</sub>|<sub>`#{{DAYS_SINCE}} days ago`</sub>|\n\n<br>\n\n---\n\n<br>\n\n### What's New\nThis release contains the following changes:\n\n<br>\n\n---\n\n<br>\n\n### Statistics\nHow the files have changed:\n<ul><li><a href='#{{RELEASE_DIFF}}'>Changed files</a> : <b>#{{CHANGED_FILES}}</b></li><li>Changes : <b>#{{CHANGES}}</b></li><li>Commits : <b>#{{COMMITS}}</b></li><li>Additions : <b>#{{ADDITIONS}}</b></li><li>Deletions : <b>#{{DELETIONS}}</b></li><li>PRs (categorized) : <b>#{{CATEGORIZED_COUNT}}</b></li><li>PRs (uncategorized) : <b>#{{UNCATEGORIZED_COUNT}}</b></li><li>PRs (open) : <b>#{{OPEN_COUNT}}</b></li>\n<br />\n</ul>\n\n<br>\n\n---\n\n<br>\n\n### Commits (#{{UNCATEGORIZED_COUNT}})\nThe following commits are uncategorized:\n#{{UNCATEGORIZED}}\n\n<br>\n\n---\n\n<br>\n\n### Pull Requests\nThis release is associated with the following pull requests:\n#{{CHANGELOG}}\n\n<br>\n\n"
                    }
              env:
                  GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN }}

            # #
            #   Release › Changelog › Convert step into ENV
            #
            #   This is a requirement in order for the action mikepenz/release-changelog-builder-action@v5 to work properly.
            #   If you use special characters like quotes and tildes in your push comments, bash will have no way of knowing
            #   if it's part of the changelog, or code itself.
            #
            #   By converting the step into an env var, we quote the text, and it fixes the issue.
            #
            #   For every step that you need to print the changelog text, first define the env var
            #   env:
            #       CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
            #
            #   Then you can call the changelog in the body / run command with
            #       echo "$CHANGELOG_CATEGORIZED"
            # #

            - name: '🙊 Changelog › Step to Env › Categorized'
              id: task_release_changelog_escape_categorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, false ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, false )
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
              run: |
                  echo "$CHANGELOG_CATEGORIZED"

            - name: '🙊 Changelog › Step to Env › Uncategorized'
              id: task_release_changelog_escape_uncategorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, true ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, true )
              env:
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
              run: |
                  echo "$CHANGELOG_UNCATEGORIZED"

            # #
            #   Release › Verbose › List Tree
            # #

            - name: '⚙️ Verbose › Tree Listing'
              id: task_release_verbose_tree
              run: |
                  tree

            # #
            #   Release › Verbose › Changelog › Print Categorized
            # #

            - name: '⚙️ Verbose › Changelog › Categorized'
              id: task_release_changelog_verbose_categorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, false ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, false )
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
              run: |
                  echo
                  echo "---- CHANGELOG [ Categorized ] -----------------------------------------------"
                  echo
                  echo "$CHANGELOG_CATEGORIZED"
                  echo
                  echo "---- CHANGELOG ---------------------------------------------------------------"
                  echo

            # #
            #   Release › Verbose › Changelog › Print Uncategorized
            # #

            - name: '⚙️ Verbose › Changelog › Uncategorized'
              id: task_release_changelog_verbose_uncategorized
              if: |
                  startsWith( inputs.SHOW_UNCATEGORIZED, true ) ||
                  startsWith( env.SHOW_UNCATEGORIZED, true )
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
              run: |
                  echo
                  echo "---- CHANGELOG [ Uncategorized ] ---------------------------------------------"
                  echo
                  echo "$CHANGELOG_UNCATEGORIZED"
                  echo
                  echo "---- CHANGELOG ---------------------------------------------------------------"
                  echo

            # #
            #   Release › Post Release (Stable)
            #
            #   outputs:
            #       [RELEASE ID]:
            #           ${{ steps.task_release_bundle_rc.outputs.id
            #           ${{ steps.task_release_bundle_st.outputs.id
            # #

            - name: '🏳️ Post › Stable'
              id: task_release_bundle_st
              if: |
                  startsWith( inputs.RC_RELEASE, false ) ||
                  startsWith( env.RC_RELEASE, false )
              uses: softprops/action-gh-release@v2
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
              with:
                  token: ${{ secrets.ADMINSERV_TOKEN_CL }}
                  name: v${{ env.PACKAGE_VERSION }}
                  tag_name: ${{ env.PACKAGE_VERSION }}
                  target_commitish: ${{ github.event.inputs.branch }}
                  draft: false
                  generate_release_notes: false
                  files: |
                      ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip
                      ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
                      sha1sum.txt.asc
                      sha256sum.txt.asc
                  prerelease: false
                  body: |
                      ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                      ${{ steps.task_release_changelog_uncategorized.outputs.changelog }}

            # #
            #   Release › Post Release (Release Candidate)
            #
            #   outputs:
            #       [RELEASE ID]:
            #           ${{ steps.task_release_bundle_rc.outputs.id
            #           ${{ steps.task_release_bundle_st.outputs.id
            # #

            - name: '🏳️ Post › Release Candidate'
              id: task_release_bundle_rc
              if: |
                  startsWith( inputs.RC_RELEASE, true ) ||
                  startsWith( env.RC_RELEASE, true )
              uses: softprops/action-gh-release@v2
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
              with:
                  token: ${{ secrets.ADMINSERV_TOKEN }}
                  name: v${{ env.PACKAGE_VERSION }}
                  tag_name: ${{ env.PACKAGE_VERSION }}
                  target_commitish: ${{ github.event.inputs.branch }}
                  draft: false
                  generate_release_notes: false
                  files: |
                      ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip
                      ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
                      sha1sum.txt.asc
                      sha256sum.txt.asc
                  prerelease: false
                  body: |
                      > [!WARNING]
                      > This is a **release candidate**, which means it is not a stable release and could contain bugs. You should download it at your own risk.

                      ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                      ${{ steps.task_release_changelog_uncategorized.outputs.changelog }}

            # #
            #   Release › Print Status
            #
            #   For every step that you need to print the changelog text, first define the env var
            #   env:
            #       CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
            #
            #   Then you can call the changelog in the body / run command with
            #       echo "$CHANGELOG_CATEGORIZED"
            # #

            - name: "🎛️ Status › Print"
              id: task_release_status_print
              env:
                  CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
                  CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
              run: |
                  echo "Printing Variables"
                  echo
                  echo "---- CHANGELOG ---------------------------------------------------------------"
                  echo "$CHANGELOG_CATEGORIZED"
                  echo "$CHANGELOG_UNCATEGORIZED"
                  echo "---- CHANGELOG ---------------------------------------------------------------"
                  echo ""
                  echo ""
                  echo "---- VARIABLES ---------------------------------------------------------------"
                  echo "Package Version ............ ${{ env.PACKAGE_VERSION }}"
                  echo "Tag: Previous .............. ${{ env.TAG_LAST }}"
                  echo "Tag: Now.... ............... ${{ github.ref }}"
                  echo "Last Commit ................ ${{ env.COMMIT_LAST }}"
                  echo "ST Output ID ............... ${{ steps.task_release_bundle_st.outputs.id }}"
                  echo "RC Output ID ............... ${{ steps.task_release_bundle_rc.outputs.id }}"
                  echo "---- CHANGELOG ---------------------------------------------------------------"

            # #
            #   Release › Upload Artifacts › Release Files › Stable
            # #

            - name: >-
                📋 Upload Artifacts › Stable › ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
              id: task_release_artifact_stable
              uses: actions/upload-artifact@v4
              if: |
                  startsWith( inputs.RC_RELEASE, false ) ||
                  startsWith( env.RC_RELEASE, false )
              with:
                  name: "${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}"
                  path: ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
                  retention-days: 30

            # #
            #   Release › Upload Artifacts › Release Files › Release Candidate
            # #

            - name: >-
                📋 Upload Artifacts › RC › ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
              id: task_release_artifact_rc
              uses: actions/upload-artifact@v4
              if: |
                  startsWith( inputs.RC_RELEASE, true ) ||
                  startsWith( env.RC_RELEASE, true )
              with:
                  name: "${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}"
                  path: ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
                  retention-days: 30

    # #
    #   Job › Complete
    # #

    job-complete:
        name: >-
          🆗 Successful Deployment
        runs-on: ubuntu-latest
        needs: [ job-initialize, job-release ]
        env:
            PACKAGE_VERSION: ${{ needs.job-initialize.outputs.package_version }}
            GUID: ${{ needs.job-release.outputs.guid }}
            UUID: ${{ needs.job-release.outputs.uuid }}
        steps:

            # #
            #   Complete › Download Artifacts
            # #

            - name: "📁 Download › Saved Artifacts"
              id: task_complete_artifacts_download
              uses: actions/download-artifact@v4

            # #
            #   Complete › Get publish timestamp
            # #

            - name: >-
                🕛 Get Timestamp
              id: task_complete_timestamp_get
              run: |
                  echo "NOW=$(date +'%m-%d-%Y %H:%M:%S')" >> $GITHUB_ENV
                  echo "NOW_SHORT=$(date +'%m-%d-%Y')" >> $GITHUB_ENV
                  echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV
                  echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV

            # #
            #   Complete › Set ENVs
            # #

            - name: "🕛 Get Env Vars"
              id: task_complete_set_envs
              run: |
                  release_stable_file="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}/${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip"
                  release_stable_sha256="$(shasum --algorithm 256 ${release_stable_file} | awk '{ print $1 }')"

                  echo "FILE_STABLE=${release_stable_file}" >> $GITHUB_ENV
                  echo "SHA_STABLE=${release_stable_sha256}" >> $GITHUB_ENV

            # #
            #   Complete › Summary of publish
            # #

            - name: "🆗 Completed: ${{ env.NOW }}"
              id: task_complete_summary
              run: |
                  echo ""
                  echo ""
                  echo "| File                            | Result                        |" >> $GITHUB_STEP_SUMMARY
                  echo "| ------------------------------- | -----------------------       |" >> $GITHUB_STEP_SUMMARY
                  echo "| 📦 **Project**                  | ${{ env.PROJECT_NAME }}       |" >> $GITHUB_STEP_SUMMARY
                  echo "| 🕛 **Deploy Time**              | ${{ env.NOW }}                |" >> $GITHUB_STEP_SUMMARY
                  echo ""
                  echo "### 📄 File (${{ env.FILE_STABLE }})                              " >> $GITHUB_STEP_SUMMARY
                  echo "This is the main release. It contains all required docker files, and the TVApp2 `package.json`" >> $GITHUB_STEP_SUMMARY
                  echo "| File                            | Result                        |" >> $GITHUB_STEP_SUMMARY
                  echo "| ------------------------------- | -----------------------       |" >> $GITHUB_STEP_SUMMARY
                  echo "| 🏷️ **SHA256**                      | ${{ env.SHA_STABLE }}      |" >> $GITHUB_STEP_SUMMARY
                  echo "| 🏷️ **GUID**                        | ${{ env.GUID }}            |" >> $GITHUB_STEP_SUMMARY
                  echo "| 🏷️ **UUID**                        | ${{ env.UUID }}            |" >> $GITHUB_STEP_SUMMARY

