foxy-io 0.3.12

A configuration-driven and hyper-extensible HTTP proxy library
Documentation
on:
  push:
    tags:
      - "*-crate"

permissions:
  contents: write  # Changed from read to write for release creation
  checks: write

name: Publish Crate Workflow

jobs:
  audit:
    name: Audit
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - name: "Generate Cargo.lock"
        run: cargo generate-lockfile

      - name: cargo-audit cache restore
        id: cargo-audit_cache_restore
        uses: actions/cache/restore@v4
        with:
          path: ~/.cargo/bin/cargo-audit
          key: ${{ runner.os }}-cargo-audit

      - run: cargo install cargo-audit
        if: steps.cargo-audit_cache_restore.outputs.cache-hit != 'true'

      - name: cargo-audit cache save
        id: cargo-audit_cache_save
        uses: actions/cache/save@v4
        if: always() && steps.cargo-audit_cache_restore.outputs.cache-hit != 'true'
        with:
          path: ~/.cargo/bin/cargo-audit
          key: ${{ runner.os }}-cargo-audit

      - uses: rustsec/audit-check@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

  build_and_test_linux:
    name: Build and Test (Linux)
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4

      - name: Install Protobuf compiler
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y protobuf-compiler
      - uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry restore
        id: cargo_cache_restore_linux
        uses: actions/cache/restore@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-

      - name: "Build and test"
        run: |
          cargo install cargo-nextest
          cargo nextest run --all-features --test-threads=1

      - name: Cache cargo registry save
        id: cargo_cache_save_linux
        uses: actions/cache/save@v4
        if: always() && steps.cargo_cache_restore_linux.outputs.cache-hit != 'true'
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

  build_and_test_windows:
    name: Build and Test (Windows)
    runs-on: windows-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4

      - name: Install Protobuf compiler
        run: choco install protoc --no-progress -y
        shell: powershell

      - name: Cache cargo registry restore
        id: cargo_cache_restore_windows
        uses: actions/cache/restore@v4
        with:
         path: |
           ~/.cargo/registry
           ~/.cargo/git
           target
         key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
         restore-keys: |
           ${{ runner.os }}-cargo-

      - uses: dtolnay/rust-toolchain@stable
      - name: "Build and test"
        run: |
          cargo install cargo-nextest
          cargo nextest run --all-features --test-threads=1

      - name: Cache cargo registry save
        id: cargo_cache_save_windows
        uses: actions/cache/save@v4
        if: always() && steps.cargo_cache_restore_windows.outputs.cache-hit != 'true'
        with:
         path: |
           ~/.cargo/registry
           ~/.cargo/git
           target
         key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

  crates_io_publish:
    name: Publish (crates.io)
    needs:
      - audit
      - build_and_test_linux
      - build_and_test_windows

    runs-on: ubuntu-latest
    timeout-minutes: 25
    steps:
      - uses: actions/checkout@v4
      - name: Install Protobuf compiler
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y protobuf-compiler
      - uses: dtolnay/rust-toolchain@stable

      - name: cargo-release cache restore
        id: cargo_release_cache_restore
        uses: actions/cache/restore@v4
        with:
          path: ~/.cargo/bin/cargo-release
          key: ${{ runner.os }}-cargo-release

      - run: cargo install cargo-release
        if: steps.cargo_release_cache_restore.outputs.cache-hit != 'true'

      - name: cargo-release cache save
        id: cargo_release_cache_save
        uses: actions/cache/save@v4
        if: always() && steps.cargo_release_cache_restore.outputs.cache-hit != 'true'
        with:
          path: ~/.cargo/bin/cargo-release
          key: ${{ runner.os }}-cargo-release

      - name: cargo login
        run: |-
          echo "${{ secrets.CRATES_IO_API_TOKEN }}" | cargo login

      - name: "cargo release publish"
        run: |-
          cargo release \
            publish \
            --workspace \
            --all-features \
            --allow-branch HEAD \
            --no-confirm \
            --no-verify \
            --execute

  tag_docker_version:
    name: Tag Docker Version
    needs:
      - crates_io_publish
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract version from tag
        id: extract_version
        run: |
          # Extract version from tag (remove -crate suffix)
          TAG_NAME=${GITHUB_REF#refs/tags/}
          VERSION=${TAG_NAME%-crate}
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "docker_tag_name=${VERSION}-docker" >> $GITHUB_OUTPUT
          echo "Extracted version: $VERSION"
          echo "Docker tag name will be: ${VERSION}-docker"

      - name: Check if Docker tag exists
        id: check_docker_tag
        run: |
          DOCKER_TAG_NAME="${{ steps.extract_version.outputs.docker_tag_name }}"
          if git rev-parse "refs/tags/$DOCKER_TAG_NAME" >/dev/null 2>&1; then
            echo "exists=true" >> $GITHUB_OUTPUT
            echo "Docker tag $DOCKER_TAG_NAME already exists"
          else
            echo "exists=false" >> $GITHUB_OUTPUT
            echo "Docker tag $DOCKER_TAG_NAME does not exist"
          fi

      - name: Create and push Docker tag
        if: steps.check_docker_tag.outputs.exists == 'false'
        run: |
          DOCKER_TAG_NAME="${{ steps.extract_version.outputs.docker_tag_name }}"
          VERSION="${{ steps.extract_version.outputs.version }}"

          # Configure git
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"

          # Create annotated tag
          git tag -a "$DOCKER_TAG_NAME" -m "Auto-tag for Docker version $VERSION"

          # Push the tag
          git push origin "$DOCKER_TAG_NAME"

          echo "Created and pushed Docker tag: $DOCKER_TAG_NAME"

      - name: Docker tag already exists
        if: steps.check_docker_tag.outputs.exists == 'true'
        run: |
          echo "Docker tag ${{ steps.extract_version.outputs.docker_tag_name }} already exists, skipping tag creation"

  create_github_release:
    name: Create GitHub Release
    needs:
      - audit
      - build_and_test_linux
      - build_and_test_windows
      - crates_io_publish
      - tag_docker_version

    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Fetch full history for changelog generation

      - name: Extract version from tag
        id: extract_version
        run: |
          # Extract version from tag (remove -crate suffix)
          TAG_NAME=${GITHUB_REF#refs/tags/}
          VERSION=${TAG_NAME%-crate}
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT

      - name: Build Changelog
        id: build_changelog
        uses: mikepenz/release-changelog-builder-action@v4
        with:
          configuration: |
            {
              "categories": [
                {
                  "title": "## ๐Ÿš€ Features",
                  "labels": ["feature", "enhancement"]
                },
                {
                  "title": "## ๐Ÿ› Bug Fixes",
                  "labels": ["bug", "fix"]
                },
                {
                  "title": "## ๐Ÿ“š Documentation",
                  "labels": ["documentation", "docs"]
                },
                {
                  "title": "## ๐Ÿ”ง Maintenance",
                  "labels": ["maintenance", "chore", "dependencies"]
                },
                {
                  "title": "## ๐Ÿ”’ Security",
                  "labels": ["security"]
                },
                {
                  "title": "## โšก Performance",
                  "labels": ["performance"]
                },
                {
                  "title": "## ๐Ÿงช Testing",
                  "labels": ["test", "testing"]
                },
                {
                  "title": "## ๐Ÿ”„ Other Changes",
                  "labels": []
                }
              ],
              "template": "#{{CHANGELOG}}\n\n## ๐Ÿ“ฆ Installation\n\n### Cargo\n```bash\ncargo add foxy-io@${{ steps.extract_version.outputs.version }}\n```\n\n### From Source\n```bash\ngit clone https://github.com/johan-steffens/foxy.git\ncd foxy\ncargo build --release\n```\n\n## ๐Ÿ”— Links\n- [๐Ÿ“ฆ Crates.io](https://crates.io/crates/foxy-io)\n- [๐Ÿ“– Documentation](https://docs.rs/foxy-io)\n- [๐Ÿ› Report Issues](https://github.com/johan-steffens/foxy/issues)\n\n---\n\n**Full Changelog**: https://github.com/johan-steffens/foxy/compare/{{PREVIOUS_TAG}}...{{TO_TAG}}"
            }
          toTag: ${{ steps.extract_version.outputs.tag_name }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.extract_version.outputs.tag_name }}
          name: "foxy-io v${{ steps.extract_version.outputs.version }}"
          body: ${{ steps.build_changelog.outputs.changelog }}
          draft: false
          prerelease: ${{ contains(steps.extract_version.outputs.version, 'alpha') || contains(steps.extract_version.outputs.version, 'beta') || contains(steps.extract_version.outputs.version, 'rc') }}
          generate_release_notes: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}