#!/bin/bash -e
# shellcheck disable=SC2103
# Copyright 2016-2019 SUSE LLC
# SPDX-License-Identifier: GPL-2.0-or-later

# The script runs in three major modes:
# * only check that documentation generation doesn't show errors
# * PUBLISH changes to upstream project
# * PUBLISH changes to new branch in fork project and create Pull Request to
# upstream project
#
# First mode (PUBLISH is not set) is to run in CI as part of regular test
# workflow
# Second mode (PUBLISH is set) is to run manually from local environment when
# need to publish documentation to upstream
# Third mode (PULL_REQUEST_USER is set) is to run from CI nightly job

# Example usages:
# PUBLISH=1 tools/generate-documentation https://github.com/andrii-suse/openQA.git gh-pages
# PUBLISH=1 GITHUB_TOKEN=xxxx271e PULL_REQUEST_USER=andrii-suse tools/generate-documentation https://token@github.com/openqabot/openQA.git gh-pages-$(date +%y%m%d%H%M%S)

# The script accepts input arguments:
# $1 - target repo (which repository is used for documentation commit),
# defaults to current repo
# $2 - target branch, defaults to gh-pages

# the script uses environment variables:
# PUBLISH - non-empty string indicates that commit should be pushed back to
# target repo (authentication must be set up in advance)
# PULL_REQUEST_USER - if set, then will be appended with ':gh-pages' and
# passed to  `hub pull-request` command
# (authentication must be set up in advance)
# If PULL_REQUEST_USER is set, then target branch ($2) must not exists at
# target remote ($1). Target branch will be created based on
# PULL_REQUEST_USER:gh_pages
# KEEP_OUTPUT - keep the output directory so the (locally) generated documentation
# can be found under out/docs/index.html after running the script
# FORMATS - white-space separated list of formats to generate; defaults to "html pdf"

set -eo pipefail

# exit status 0 if any changes detected
anything_changed() {
    echo '*.pdf -diff' >> .gitattributes
    git --no-pager diff --shortstat

    local lines_changed_in_index lines_changed_in_api other_files_changed

    # it looks it is a challenge to ignore lines in git diff
    lines_changed_in_index="$(git --no-pager diff -U0 -- index.html     | grep -v -e 'Last updated ' -e '^\@\@' -e '+++ b' -e '^index ' -e '--- a' | tail -n +2 | wc -l)"
    lines_changed_in_api="$(git --no-pager diff -U0 -- api/testapi.html | grep -v -e 'Last updated ' -e '^\@\@' -e '+++ b' -e '^index ' -e '--- a' | tail -n +2 | wc -l)"
    other_files_changed="$(git --no-pager diff --name-only -- '(:!index.html)' '(:!api/testapi.html)' '(:!current.pdf)' | wc -l)"

    # if any other file changed || any line besides containing 'Last Updated' in .html
    test "$other_files_changed" -gt 0 || test "$((lines_changed_in_index+lines_changed_in_api))" -gt 0
}

check_branch_exists() {
    local repo=$1
    local branch=$2

    if git ls-remote --exit-code -- "$repo" "$branch" ; then
        return
    fi

    echo "Branch $branch is not found at $repo, exiting"
    (exit 1)
}

update_docs() {
        mkdir out || exit 1
        (
        cd out
        # shellcheck disable=SC2030
        if [[ -z "${PULL_REQUEST_USER}" ]]; then
            git clone --depth 1 --branch "$PUSH_BRANCH" "$PUSH_REMOTE_URL" .
        else
            # we cannot have --depth here because will push to new branch
            git clone --branch gh-pages "https://github.com/$PULL_REQUEST_USER/openQA" .
            git checkout -b "$PUSH_BRANCH"
        fi

        if [ -n "${COMMIT_AUTHOR_EMAIL}" ]; then
            git config user.name "CI"
            git config user.email "$COMMIT_AUTHOR_EMAIL"
        fi
        mkdir -p docs
        cp -r "${tmpwd}"/output/* docs
        cd docs
        ls -l
        git add images
        update_api
        update_schemas
        [[ ${formats[html]} ]] && ln -f openqa-documentation-"${verbose_doc_name}".html index.html
        [[ ${formats[pdf]} ]] && ln -f openqa-documentation-"${verbose_doc_name}".pdf current.pdf
        if [[ ${formats[html]} ]] && anything_changed; then
            cd ..
            git add _includes/api.html
            git add docs/index.html docs/current.pdf docs/api/testapi.html
            git add docs/api/schema
            topic="Update documentation to commit ${shortref}"
            echo "$topic" > last.commit
            echo "" >> last.commit
            [[ -z "${CIRCLE_SHA1}" ]] || (cd .. && git log --pretty=fuller "${CIRCLE_SHA1}" -1 >> out/last.commit)
            git commit -F last.commit
            if [[ -n "${PUBLISH}" ]] && [[ "${PUBLISH}" != 0 ]]; then
                git push "$PUSH_REMOTE_URL" "$PUSH_BRANCH"
                if [[ -n "${PULL_REQUEST_USER}" ]]; then
                    # convert PUSH_REMOTE_URL to hub format (extract user from url)
                    local push_user_url
                    push_user_url="$(dirname "$PUSH_REMOTE_URL")"
                    local push_user
                    push_user="$(basename "$push_user_url")"
                    hub pull-request -m "$topic" --base "${PULL_REQUEST_USER}:gh-pages" --head "$push_user:$PUSH_BRANCH"
                fi
            fi
            cd ..
        else
            echo Documentation is up to date
        fi
        )
        [[ $KEEP_OUTPUT ]] || rm -rf out
}

update_api() {
        mkdir -p api/src
        curl -o api/src/testapi.pm https://raw.githubusercontent.com/os-autoinst/os-autoinst/master/testapi.pm
        cd api
        "${scriptroot}"/generate-documentation-genapi

        find . -name '*.asciidoc' -not -name 'header' -exec "${asciidoctor_bin}" {} \;
        while IFS= read -r -d '' file
        do
            header_template "$file" > "$file.tmp"
            cat "$file" >> "$file.tmp"
            mv "$file.tmp" "$file"
        done < <(find . -name '*.html' -print0)
        cd ..
}

update_schemas() {
        mkdir -p api/schema
        cp "$scriptroot"/../public/schema/* api/schema
}

header_template() {
filename=$( basename -s .html "$1" )
cat <<APIFILE
---
layout: null
categories: [api]
title: ${filename}
permalink: /api/${filename}/
---
APIFILE

}

green="\e[23m\e[1m"

asciidoctor_bin="/bin/not/set"
shortref=$(git rev-parse --short HEAD)
verbose_doc_name=$(date +%Y%m%d)"_"${shortref} #we are not intending to run this off a git repository
scriptroot="$( cd "$(dirname "$0")" ; pwd -P )"
tmpwd=$(mktemp -d -t openqa-doc-XXXX)
PUSH_REMOTE_URL="${1:-$(git config --get remote.origin.url)}"
PUSH_BRANCH="${2:-gh-pages}"
declare -A formats
for format in ${FORMATS:-pdf html}; do formats["$format"]=1; done

# if target branch doesn't exits we just exit
# shellcheck disable=SC2031
if [[ -z "${PULL_REQUEST_USER}" ]]; then
    check_branch_exists "$PUSH_REMOTE_URL" "$PUSH_BRANCH" || exit 0
else
    check_branch_exists "https://github.com/$PULL_REQUEST_USER/openQA" "gh-pages" || exit 0
fi

check_asciidoctor() {
    asciidoctor_bin=$(command -v asciidoctor) || true
    [[ -n "$asciidoctor_bin" ]] || \
        for asciidoctor_bin in "${GEM_HOME}"/bin/asciidoctor.ruby*; do :; done

    if [[ -z "$asciidoctor_bin" ]] || [[ ! -f $asciidoctor_bin ]]; then
        echo "Could not find asciidoctor binary in your path, please install it and run this command again:"
        echo "    sudo gem install asciidoctor pygments.rb"
        [[ ${formats[pdf]} ]] && echo "    sudo gem install asciidoctor-pdf --pre"
        echo "    sudo zypper install ruby2.6-rubygem-asciidoctor"
        echo "    sudo zypper install 'perl(Pod::AsciiDoctor)'"
        exit 1
    fi
}

install_asciidoctor() {
    # install dependencies
    gem install asciidoctor pygments.rb
    [[ ${formats[pdf]} ]] && gem install asciidoctor-pdf --pre
    cpanm -M https://cpan.metacpan.org --install Pod::AsciiDoctor
}

call_asciidoctor() {

    check_asciidoctor

    cd docs
    mkdir "${tmpwd}"/output 2>/dev/null || true  # we don't care if the directory already exists
    cp -r images "${tmpwd}"/output

    [[ ${formats[pdf]} ]] \
        && "${asciidoctor_bin}" -r asciidoctor-pdf -b pdf -o "${tmpwd}"/output/openqa-documentation-"${verbose_doc_name}".pdf index.asciidoc -d book
    [[ ${formats[html]} ]] \
        && "${asciidoctor_bin}" -o "${tmpwd}"/output/openqa-documentation-"${verbose_doc_name}".html index.asciidoc -d book

    echo -e  "${green}The output has been generated at ${tmpwd}/output"

    cd ..
}

if [[ -n ${CI} ]]; then
    cpanm -M https://cpan.metacpan.org --local-lib=~/perl5 local::lib && eval "$(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)"
    install_asciidoctor
fi

call_asciidoctor
update_docs
