kiteticker-async-manager 0.4.0

High-performance async WebSocket client for Kite Connect API with multi-connection support, dynamic subscription management, and optimized data processing.
Documentation
name: Release Automation Template

on:
  # Disable automatic triggers since auto-release script handles everything
  # push:
  #   branches:
  #     - main
  #     - master
  #     - 'v[0-9]+'  # Support major version branches (v1, v2, etc.)
  workflow_dispatch:  # Allow manual trigger only
    inputs:
      version:
        description: 'Version to release (leave empty to use Cargo.toml version)'
        required: false
        type: string
      skip_tests:
        description: 'Skip test execution (emergency releases only)'
        required: false
        type: boolean
        default: false

env:
  CARGO_TERM_COLOR: always

permissions:
  contents: write  # Required to create tags and releases
  packages: read   # Required for caching
  pull-requests: write  # Required for PR comments

jobs:
  check-tag:
    name: Check Release Prerequisites
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version-check.outputs.version }}
      tag-exists: ${{ steps.version-check.outputs.tag-exists }}
      is-major-branch: ${{ steps.version-check.outputs.is-major-branch }}
      should-release: ${{ steps.version-check.outputs.should-release }}
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0  # Fetch all tags and history
    
    - name: Check version and release conditions
      id: version-check
      run: |
        # Get version from input or Cargo.toml
        if [[ -n "${{ github.event.inputs.version }}" ]]; then
          VERSION="${{ github.event.inputs.version }}"
          echo "Using input version: $VERSION"
        else
          VERSION=$(grep "^version" Cargo.toml | sed 's/version = "\(.*\)"/\1/')
          echo "Using Cargo.toml version: $VERSION"
        fi
        
        echo "version=$VERSION" >> $GITHUB_OUTPUT
        echo "Current version: $VERSION"
        
        # Check if we're on a major version branch
        BRANCH_NAME="${{ github.ref_name }}"
        if [[ $BRANCH_NAME =~ ^v[0-9]+$ ]]; then
          echo "is-major-branch=true" >> $GITHUB_OUTPUT
          echo "On major version branch: $BRANCH_NAME"
        else
          echo "is-major-branch=false" >> $GITHUB_OUTPUT
          echo "On main/master branch: $BRANCH_NAME"
        fi
        
        # Check if tag already exists
        if git tag | grep -q "^v$VERSION$"; then
          echo "tag-exists=true" >> $GITHUB_OUTPUT
          echo "should-release=false" >> $GITHUB_OUTPUT
          echo "โš ๏ธ Tag v$VERSION already exists - skipping release"
        else
          echo "tag-exists=false" >> $GITHUB_OUTPUT
          echo "should-release=true" >> $GITHUB_OUTPUT
          echo "โœ… Tag v$VERSION does not exist - proceeding with release"
        fi

  test:
    name: Test Before Release
    runs-on: ubuntu-latest
    needs: check-tag
    if: needs.check-tag.outputs.should-release == 'true' && github.event.inputs.skip_tests != 'true'
    strategy:
      matrix:
        rust: [stable]
        include:
          - rust: stable
            coverage: true
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust ${{ matrix.rust }}
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: ${{ matrix.rust }}
    
    - name: Cache cargo
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-release-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Run comprehensive test suite
      run: |
        echo "๐Ÿงช Running comprehensive test suite..."
        cargo test --verbose --all-features
        cargo test --doc --all-features
        cargo test --no-default-features
    
    - name: Build release
      run: cargo build --release --all-features
    
    - name: Test package publishing
      run: cargo publish --dry-run --all-features

  security-audit:
    name: Security Audit
    runs-on: ubuntu-latest
    needs: check-tag
    if: needs.check-tag.outputs.should-release == 'true'
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    
    - name: Install cargo-audit
      run: cargo install cargo-audit --locked
    
    - name: Run security audit
      run: cargo audit

  create-tag:
    name: Create Release Tag
    runs-on: ubuntu-latest
    needs: [check-tag, test, security-audit]
    if: |
      always() && 
      needs.check-tag.outputs.should-release == 'true' && 
      (needs.test.result == 'success' || github.event.inputs.skip_tests == 'true') &&
      needs.security-audit.result == 'success'
    outputs:
      tag: ${{ steps.create-tag.outputs.tag }}
      changelog: ${{ steps.generate-changelog.outputs.changelog }}
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    
    - name: Configure Git
      run: |
        git config user.name "github-actions[bot]"
        git config user.email "github-actions[bot]@users.noreply.github.com"
    
    - name: Generate changelog
      id: generate-changelog
      run: |
        VERSION="${{ needs.check-tag.outputs.version }}"
        
        # Get the latest tag to generate changelog from
        LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
        
        if [[ -n "$LATEST_TAG" ]]; then
          echo "Generating changelog from $LATEST_TAG to HEAD"
          CHANGELOG=$(git log --pretty=format:"- %s" "$LATEST_TAG"..HEAD | head -20)
        else
          echo "No previous tags found, generating changelog from all commits"
          CHANGELOG=$(git log --pretty=format:"- %s" HEAD | head -20)
        fi
        
        # Create a safe changelog for GitHub
        {
          echo "changelog<<EOF"
          echo "$CHANGELOG"
          echo "EOF"
        } >> $GITHUB_OUTPUT
    
    - name: Create annotated tag
      id: create-tag
      run: |
        VERSION="${{ needs.check-tag.outputs.version }}"
        TAG="v$VERSION"
        
        # Create annotated tag with release information
        TAG_MESSAGE="Release $TAG
        
        Version: $VERSION
        Branch: ${{ github.ref_name }}
        Commit: ${{ github.sha }}
        
        Automated release created by GitHub Actions"
        
        git tag -a "$TAG" -m "$TAG_MESSAGE"
        git push origin "$TAG"
        
        echo "tag=$TAG" >> $GITHUB_OUTPUT
        echo "โœ… Created and pushed tag: $TAG"

  publish-crate:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    needs: [check-tag, create-tag]
    if: success()
    steps:
    - uses: actions/checkout@v4
      with:
        ref: ${{ needs.create-tag.outputs.tag }}
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    
    - name: Cache cargo
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-publish-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Final validation before publish
      run: |
        echo "๐Ÿ” Final validation before publishing..."
        cargo build --release --all-features
        cargo test --all-features
        cargo publish --dry-run --all-features

    - name: Check if version already exists on crates.io
      id: version-check
      run: |
        set -euo pipefail
        VERSION="${{ needs.check-tag.outputs.version }}"
        NAME="${{ github.event.repository.name }}"
        if cargo search "^${NAME}$" --limit 1 | grep -q "${NAME} = \"${VERSION}\""; then
          echo "exists=true" >> "$GITHUB_OUTPUT"
          echo "Version $VERSION already exists on crates.io"
        else
          echo "exists=false" >> "$GITHUB_OUTPUT"
          echo "Version $VERSION not found on crates.io"
        fi
    
    - name: Publish to crates.io
      if: steps.version-check.outputs.exists == 'false'
      run: |
        echo "๐Ÿ“ฆ Publishing to crates.io..."
        cargo publish --all-features
      env:
        CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

    - name: Skip publish (version exists)
      if: steps.version-check.outputs.exists == 'true'
      run: "echo \"Skipping publish: version ${{ needs.check-tag.outputs.version }} already exists on crates.io\""

  create-github-release:
    name: Create GitHub Release
    runs-on: ubuntu-latest
    needs: [check-tag, create-tag, publish-crate]
    if: success()
    steps:
    - uses: actions/checkout@v4
      with:
        ref: ${{ needs.create-tag.outputs.tag }}
    
    - name: Extract version info
      id: version-info
      run: |
        VERSION="${{ needs.check-tag.outputs.version }}"
        TAG="${{ needs.create-tag.outputs.tag }}"
        
        # Determine version type
        IFS='.' read -r major minor patch <<< "$VERSION"
        if [[ $patch == "0" && $minor == "0" ]]; then
          VERSION_TYPE="Major Release ๐Ÿ”ฅ"
          EMOJI="๐Ÿ”ฅ"
        elif [[ $patch == "0" ]]; then
          VERSION_TYPE="Minor Release โœจ"
          EMOJI="โœจ"
        else
          VERSION_TYPE="Patch Release ๐Ÿ›"
          EMOJI="๐Ÿ›"
        fi
        
        echo "version-type=$VERSION_TYPE" >> $GITHUB_OUTPUT
        echo "emoji=$EMOJI" >> $GITHUB_OUTPUT
    
    - name: Create GitHub Release
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ needs.create-tag.outputs.tag }}
        release_name: "${{ steps.version-info.outputs.emoji }} Release ${{ needs.create-tag.outputs.tag }}"
        body: |
          # ${{ steps.version-info.outputs.version-type }}
          
          **Version:** ${{ needs.check-tag.outputs.version }}
          **Branch:** ${{ github.ref_name }}
          **Published to:** [crates.io](https://crates.io/crates/${{ github.event.repository.name }}) (if not already existing)
          
          ## What's Changed
          ${{ needs.create-tag.outputs.changelog }}
          
          ## Installation
          ```toml
          [dependencies]
          ${{ github.event.repository.name }} = "${{ needs.check-tag.outputs.version }}"
          ```
          
          ## Documentation
          - [docs.rs](https://docs.rs/${{ github.event.repository.name }}/${{ needs.check-tag.outputs.version }})
          - [Repository](https://github.com/${{ github.repository }})
          
          ---
          *This release was automatically created by GitHub Actions*
        draft: false
        prerelease: false

  post-release-notification:
    name: Post-Release Notifications
    runs-on: ubuntu-latest
    needs: [check-tag, create-tag, publish-crate, create-github-release]
    if: always()
    steps:
    - name: Notify release status
      run: |
        VERSION="${{ needs.check-tag.outputs.version }}"
        TAG="${{ needs.create-tag.outputs.tag }}"
        
        if [[ "${{ needs.create-github-release.result }}" == "success" ]]; then
          echo "๐ŸŽ‰ Release $TAG completed successfully!"
          if [[ "${{ needs.publish-crate.result }}" == "success" ]]; then
            echo "โœ… Published to crates.io"
          else
            echo "โ„น๏ธ Skipped publishing (version already existed on crates.io)"
          fi
          echo "โœ… GitHub release created"
          echo "๐Ÿ”— https://crates.io/crates/${{ github.event.repository.name }}"
          echo "๐Ÿ”— https://github.com/${{ github.repository }}/releases/tag/$TAG"
        else
          echo "โŒ Release $TAG failed!"
          echo "Crate publish: ${{ needs.publish-crate.result }}"
          echo "GitHub release: ${{ needs.create-github-release.result }}"
        fi