name: Go Releaser
on: [push]

jobs:
  # build the goreleaser container cgo cross compiler container. Note: this wil not be applied  until
  # the next run since build-goreleaser and run-goreleaser are run concurrently. We expect github actions
  # to fix this in a future version.
  build-goreleaser:
    runs-on: ubuntu-latest
    outputs:
      goreleaser-image: ${{ steps.name-export.outputs.TAG_NAME }}
    permissions:
      # always required
      packages: write
      # only required for private repos
      actions: read
      contents: write
    steps:
      - name: Git Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # needed if using new-from-rev (see: https://golangci-lint.run/usage/configuration/#issues-configuration)
          submodules: true


      - name: Cache Docker images.
        uses: ScribeMD/docker-cache@0.3.6
        with:
          key: docker-release-${{ runner.os }}-${{ matrix.package }}

      - uses: dorny/paths-filter@v2
        name: check if any changes warrant a new build of goreleaser-cgo-cross-compiler
        id: changes
        with:
          token:  ${{ secrets.GITHUB_TOKEN }}
          filters: |
            src:
              - 'docker/goreleaser/**'
      -
        name: Set up Docker Buildx
        if: steps.changes.outputs.src == 'true'
        uses: docker/setup-buildx-action@v2
        with:
          driver-opts: network=host

      - name: Environment variables
        # TODO: this if block needs to be run on every step now, but should be fixed in a future version: https://github.com/actions/runner/issues/662
        if: steps.changes.outputs.src == 'true'
        uses: franzdiebold/github-env-vars-action@v1.0.0
        env:
          ACTIONS_ALLOW_UNSECURE_COMMANDS: true

      -
        name: Login to GitHub Container Registry
        if: steps.changes.outputs.src == 'true'
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # we do this so we can use it in subseuqnet steps
      - name: Export latest tag name
        id: name-export
        run:
          echo "##[set-output name=TAG_NAME;]$(echo $LATEST_TAG_NAME)"
        env:
          LATEST_TAG_NAME: ghcr.io/synapsecns/sanguine-goreleaser:${{ hashFiles('docker/goreleaser/**') }}
      -
        name: Build and push
        if: steps.changes.outputs.src == 'true'
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          file: ./docker/goreleaser/Dockerfile
          # TODO this needs to be versioned
          # Note: this automatically pushes the latest tag for sanguine-goreleaser even on branched workflows. While unlikely,
          # this could break local devnets that rely on working versions of this image and as such the latest tag should only be pushed on master
          # additionally, tags representing a specific version rather than the hash of the file should be considered for future use.
          tags: ghcr.io/synapsecns/sanguine-goreleaser:latest,${{ steps.name-export.outputs.TAG_NAME }}
          cache-from: type=registry,ref=ghcr.io/synapsecns/sanguine-goreleaser:buildcache
          cache-to: type=registry,ref=ghcr.io/synapsecns/sanguine-goreleaser:buildcache,mode=max

  # TODO: we should find a way for this not to be duplicated with go.yml
  changes:
    name: Change Detection
    runs-on: ubuntu-latest
    # see: https://stackoverflow.com/a/68414395
    if: ${{ format('refs/heads/{0}', github.event.repository.default_branch) == github.ref || contains(github.event.head_commit.message, '[goreleaser]') }}
    outputs:
      # Expose matched filters as job 'packages' output variable
      packages: ${{ steps.filter_go.outputs.changed_modules_deps }}
      package_count: ${{ steps.length.outputs.FILTER_LENGTH }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: 'recursive'

      - uses: docker://ghcr.io/synapsecns/sanguine/git-changes-action:latest
        id: filter_go
        with:
          github_token: ${{ secrets.WORKFLOW_PAT }}

      - id: length
        run: |
          export FILTER_LENGTH=$(echo $FILTERED_PATHS | jq '. | length')
          echo "##[set-output name=FILTER_LENGTH;]$(echo $FILTER_LENGTH)"
        env:
          FILTERED_PATHS: ${{ steps.filter_go.outputs.changed_modules_deps }}

  # TODO: we may want to dry run this on prs
  run-goreleaser:
    runs-on: ubuntu-latest
    needs: [build-goreleaser,changes]
    if: ${{ needs.changes.outputs.package_count > 0 }}
    permissions:
      # always required
      packages: write
      # only required for private repos
      actions: read
      contents: write
    strategy:
      fail-fast: false
      matrix:
        # list of packages, if you update this update changes as well
        package: ${{ fromJSON(needs.changes.outputs.packages) }}
    container:
      image: ${{ needs.build-goreleaser.outputs.goreleaser-image }}
      volumes: [ /repo ]
    steps:
      - name: Git Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: 'recursive'


      - name: Get branch name
        id: branch-name
        uses: tj-actions/branch-names@v6

      - name: Bump version and push tag
        id: tag_version
        if: steps.branch-name.outputs.is_default == 'true'
        uses: mathieudutour/github-tag-action@v6.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          tag_prefix: ${{matrix.package}}/v
          release_branches: master
          fetch_all_tags: true

      - name: Tag Config
        run: git config --global --add safe.directory /__w/sanguine/sanguine

      -
        name: Fetch all tags
        run: git fetch --force --tags

      # get the tag we just created
      - name: Git Fetch Unshallow
        run: git fetch

      - name: Import GPG key
        uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0
        id: import_gpg
        with:
          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.GPG_PASSPHRASE }}

      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: 1.20.x

      -
        name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Run GoReleaser (Release)
        if: steps.branch-name.outputs.is_default == 'true'
        run: goreleaser  --timeout 900m --clean --debug -f ${{matrix.package}}/.goreleaser.yml
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GONOSUM: '.*'
          GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
          GOGC: 2000
          GOMEMLIMIT: 6GiB
          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}

      # use this to determine if we need goreleaser for a workflow
      # TODO: it might be worth considering moving this into a seperate workflow so we can avoid doing a full clone + pulling the image when we don't need anything
      - name: Check For Docker Images
        if: steps.branch-name.outputs.is_default != 'true'
        id: image_check
        run: |
          # will be 0 if none present
          has_images=$(yq eval '.dockers != null' ${{matrix.package}}/.goreleaser.yml)
          echo "##[set-output name=has_images;]$(echo $has_images)"


      - name: Run GoReleaser (Snapshot)
        if: steps.branch-name.outputs.is_default != 'true' && steps.image_check.outputs.has_images == 'true'
        run: goreleaser --timeout 900m --snapshot --clean --debug -f ${{matrix.package}}/.goreleaser.yml
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GONOSUM: '.*'
          GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
          GOGC: 20
          GOMEMLIMIT: 6GiB
          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}

      - name: Get Project Name
        id: project_id
        run: |
          project_name=$(yq '.project_name' ${{matrix.package}}/.goreleaser.yml)
          echo "##[set-output name=project_name;]$(echo $project_name)"

      - name: Push Docker Images (Snapshot)
        if: steps.branch-name.outputs.is_default != 'true' && steps.image_check.outputs.has_images == 'true'
        run: |
          docker_image=$(yq '.dockers | length' dist/config.yaml)
          if [ $docker_image -eq "0" ]; then
            echo "No docker images to push"
            exit 0
          fi
          docker tag ghcr.io/synapsecns/sanguine/$image_name:latest ghcr.io/synapsecns/$image_name:${GITHUB_SHA}
          docker push ghcr.io/synapsecns/sanguine/$image_name:${GITHUB_SHA}
        env:
          image_name: ${{ steps.project_id.outputs.project_name }}

      - name: Zip Artifacts (Snapshot)
        if: steps.branch-name.outputs.is_default != 'true' && steps.image_check.outputs.has_images == 'true'
        run: |
            ls
            zip -rv ${{ steps.project_id.outputs.project_name }}.zip dist

      - name: Push Artifacts (Snapshot)
        if: steps.branch-name.outputs.is_default != 'true' && steps.image_check.outputs.has_images == 'true'
        uses: actions/upload-artifact@v3
        with:
          name: ${{steps.project_id.outputs.project_name}}.zip
          path: ${{steps.project_id.outputs.project_name}}.zip

      - name: Copy Releases
        if: ${{ steps.branch-name.outputs.is_default == 'true' && contains( steps.tag_version.outputs.new_tag, 'terraform-provider-iap') }}
        uses: docker://ghcr.io/synapsecns/sanguine/release-copier-action:latest
        with:
          github_token: ${{ secrets.PUBLISH_TOKEN }}
          # TODO: will change with new org
          destination_repo: 'trajan0x/terraform-provider-iap'
          tag_name: ${{ steps.tag_version.outputs.new_tag }}
          strip_prefix: 'contrib/terraform-provider-iap/'

      - name: Copy Releases
        if: ${{ steps.branch-name.outputs.is_default == 'true' && contains( steps.tag_version.outputs.new_tag, 'terraform-provider-helmproxy') }}
        uses: docker://ghcr.io/synapsecns/sanguine/release-copier-action:latest
        with:
          github_token: ${{ secrets.PUBLISH_TOKEN }}
          # TODO: will change with new org
          destination_repo: 'trajan0x/terraform-provider-helmproxy'
          tag_name: ${{ steps.tag_version.outputs.new_tag }}
          strip_prefix: 'contrib/terraform-provider-helmproxy/'

      - name: Copy Releases
        if: ${{ steps.branch-name.outputs.is_default == 'true' && contains( steps.tag_version.outputs.new_tag, 'terraform-provider-kubeproxy') }}
        uses: docker://ghcr.io/synapsecns/sanguine/release-copier-action:latest
        with:
          github_token: ${{ secrets.PUBLISH_TOKEN }}
          # TODO: will change with new org
          destination_repo: 'trajan0x/terraform-provider-kubeproxy'
          tag_name: ${{ steps.tag_version.outputs.new_tag }}
          strip_prefix: 'contrib/terraform-provider-kubeproxy/'