name: Release
on:
  workflow_dispatch:

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - run: |
          if [[ $GITHUB_REF_NAME != release/* ]]; then
            echo this workflow should only be run against release branches
            exit 1
          fi

      - uses: actions/checkout@v3

      - name: Set environment variables
        run: |
          stable_version=$(./scripts/eachdist.py version --mode stable)
          unstable_version=$(./scripts/eachdist.py version --mode prerelease)

          if [[ $stable_version =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
            stable_major="${BASH_REMATCH[1]}"
            stable_minor="${BASH_REMATCH[2]}"
            stable_patch="${BASH_REMATCH[3]}"
          else
            echo "unexpected stable_version: $stable_version"
            exit 1
          fi
          if [[ $stable_patch != 0 ]]; then
            if [[ $unstable_version =~ ^0\.([0-9]+)b([0-9]+)$ ]]; then
              unstable_minor="${BASH_REMATCH[1]}"
              unstable_patch="${BASH_REMATCH[2]}"
            else
              echo "unexpected unstable_version: $unstable_version"
              exit 1
            fi
            if [[ $unstable_patch != 0 ]]; then
              prior_version_when_patch="$stable_major.$stable_minor.$((stable_patch - 1))/0.${unstable_minor}b$((unstable_patch - 1))"
            fi
          fi

          echo "STABLE_VERSION=$stable_version" >> $GITHUB_ENV
          echo "UNSTABLE_VERSION=$unstable_version" >> $GITHUB_ENV

          echo "PRIOR_VERSION_WHEN_PATCH=$prior_version_when_patch" >> $GITHUB_ENV

        # check out main branch to verify there won't be problems with merging the change log
        # at the end of this workflow
      - uses: actions/checkout@v3
        with:
          ref: main

      - run: |
          if [[ -z $PRIOR_VERSION_WHEN_PATCH ]]; then
            # not making a patch release
            if ! grep --quiet "^## Version ${STABLE_VERSION}/${UNSTABLE_VERSION} " CHANGELOG.md; then
              echo the pull request generated by prepare-release-branch.yml needs to be merged first
              exit 1
            fi
          fi

        # back to the release branch
      - uses: actions/checkout@v3

        # next few steps publish to pypi
      - uses: actions/setup-python@v1
        with:
          python-version: '3.7'

      - name: Build wheels
        run: ./scripts/build.sh

      - name: Install twine
        run: |
          pip install twine

      # The step below publishes to testpypi in order to catch any issues
      # with the package configuration that would cause a failure to upload
      # to pypi. One example of such a failure is if a classifier is
      # rejected by pypi (e.g "3 - Beta"). This would cause a failure during the
      # middle of the package upload causing the action to fail, and certain packages
      # might have already been updated, this would be bad.
      - name: Publish to TestPyPI
        env:
          TWINE_USERNAME: '__token__'
          TWINE_PASSWORD: ${{ secrets.test_pypi_token }}
        run: |
          twine upload --repository testpypi --skip-existing --verbose dist/*

      - name: Publish to PyPI
        env:
          TWINE_USERNAME: '__token__'
          TWINE_PASSWORD: ${{ secrets.pypi_password }}
        run: |
          twine upload --skip-existing --verbose dist/*

      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # conditional block not indented because of the heredoc
          if [[ ! -z $PRIOR_VERSION_WHEN_PATCH ]]; then
          cat > /tmp/release-notes.txt << EOF
          This is a patch release on the previous $PRIOR_VERSION_WHEN_PATCH release, fixing the issue(s) below.

          EOF
          fi

          # CHANGELOG_SECTION.md is also used at the end of the release workflow
          # for copying the change log updates to main
          sed -n "0,/^## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} /d;/^## Version /q;p" CHANGELOG.md \
            > /tmp/CHANGELOG_SECTION.md

          # the complex perl regex is needed because markdown docs render newlines as soft wraps
          # while release notes render them as line breaks
          perl -0pe 's/(?<!\n)\n *(?!\n)(?![-*] )(?![1-9]+\. )/ /g' /tmp/CHANGELOG_SECTION.md \
            >> /tmp/release-notes.txt

      - name: Create GitHub release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh release create --target $GITHUB_REF_NAME \
                            --title "Version ${STABLE_VERSION}/${UNSTABLE_VERSION}" \
                            --notes-file /tmp/release-notes.txt \
                            --discussion-category announcements \
                            v$UNSTABLE_VERSION

      - uses: actions/checkout@v3
        with:
          # the step below is creating a pull request against main
          ref: main

      - name: Copy change log updates to main
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          if [[ -z $PRIOR_VERSION_WHEN_PATCH ]]; then
            # this was not a patch release, so the version exists already in the CHANGELOG.md

            # update the release date
            date=$(gh release view v$STABLE_VERSION --json publishedAt --jq .publishedAt | sed 's/T.*//')
            sed -Ei "s/## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} .*/## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} ($date)/" CHANGELOG.md

            # the entries are copied over from the release branch to support workflows
            # where change log entries may be updated after preparing the release branch

            # copy the portion above the release, up to and including the heading
            sed -n "0,/^## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} ($date)/p" CHANGELOG.md > /tmp/CHANGELOG.md

            # copy the release notes
            cat /tmp/CHANGELOG_SECTION.md >> /tmp/CHANGELOG.md

            # copy the portion below the release
            sed -n "0,/^## Version ${STABLE_VERSION}\/${UNSTABLE_VERSION} /d;0,/^## Version /{/^## Version/!d};p" CHANGELOG.md \
              >> /tmp/CHANGELOG.md

            # update the real CHANGELOG.md
            cp /tmp/CHANGELOG.md CHANGELOG.md
          else
            # this was a patch release, so the version does not exist already in the CHANGELOG.md

            # copy the portion above the top-most release, not including the heading
            sed -n "0,/^## Version /{ /^## Version /!p }" CHANGELOG.md > /tmp/CHANGELOG.md

            # add the heading
            date=$(gh release view v$STABLE_VERSION --json publishedAt --jq .publishedAt | sed 's/T.*//')
            echo "## Version ${STABLE_VERSION}/${UNSTABLE_VERSION} ($date)" >> /tmp/CHANGELOG.md

            # copy the release notes
            cat /tmp/CHANGELOG_SECTION.md >> /tmp/CHANGELOG.md

            # copy the portion starting from the top-most release
            sed -n "/^## Version /,\$p" CHANGELOG.md >> /tmp/CHANGELOG.md

            # update the real CHANGELOG.md
            cp /tmp/CHANGELOG.md CHANGELOG.md
          fi

      - name: Use CLA approved github bot
        run: .github/scripts/use-cla-approved-github-bot.sh

      - name: Create pull request against main
        env:
          # not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
          GITHUB_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
        run: |
          message="Copy change log updates from $GITHUB_REF_NAME"
          body="Copy log updates from \`$GITHUB_REF_NAME\`."
          branch="opentelemetrybot/copy-change-log-updates-from-${GITHUB_REF_NAME//\//-}"

          if [[ -z $PRIOR_VERSION_WHEN_PATCH ]]; then
            if git diff --quiet; then
              echo there are no updates needed to the change log on main, not creating pull request
              exit 0 # success
            fi
          fi

          git commit -a -m "$message"
          git push origin HEAD:$branch
          gh pr create --title "$message" \
                       --body "$body" \
                       --head $branch \
                       --base main