langfuse-client-base 0.12.0

Auto-generated Langfuse API client from OpenAPI specification
Documentation
name: Generate Client

on:
  schedule:
    # Run every night at 2 AM UTC
    - cron: '0 2 * * *'
  workflow_dispatch: # Allow manual triggering

concurrency:
  group: generate-client
  cancel-in-progress: true

permissions:
  contents: write
  pull-requests: write

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      # Mint short-lived GitHub App token (required)
      - name: Create GitHub App token
        id: app-token
        uses: actions/create-github-app-token@v3
        with:
          app-id: ${{ secrets.BOT_APP_ID }}
          private-key: ${{ secrets.BOT_PRIVATE_KEY }}

      - name: Generate client
        env:
          UPDATE_SPEC: true
        run: |
          # The script handles everything internally:
          # - Checks for Docker availability
          # - Downloads latest OpenAPI spec (only if changed)
          # - Runs generation using Docker
          # - Preserves custom files
          # - Formats the code
          chmod +x ./scripts/generate-openapi-client.sh
          ./scripts/generate-openapi-client.sh

      - name: Verify generation succeeded
        run: |
          # Ensure critical files exist
          test -f src/lib.rs || (echo "Error: src/lib.rs not found after generation" && exit 1)
          test -f Cargo.toml || (echo "Error: Cargo.toml not found after generation" && exit 1)
          
          echo "✅ Generation finished. CI will validate build/test on the PR."

      - name: Check for changes
        id: check_changes
        run: |
          # Clean any build artifacts that shouldn't be committed
          rm -rf target/
          
          # Check if there are any changes to commit
          if git diff --quiet && git diff --staged --quiet; then
            echo "No changes detected"
            echo "has_changes=false" >> $GITHUB_OUTPUT
          else
            echo "Changes detected"
            echo "has_changes=true" >> $GITHUB_OUTPUT
            # Show what changed for the PR description
            git diff --stat
          fi

      - name: Create or Update Pull Request
        id: cpr
        if: steps.check_changes.outputs.has_changes == 'true'
        uses: peter-evans/create-pull-request@v8
        with:
          token: ${{ steps.app-token.outputs.token }}
          commit-message: 'chore: update generated client from latest OpenAPI spec'
          title: 'chore: update generated client from latest OpenAPI spec'
          base: main
          add-paths: |
            src/
            Cargo.toml
            docs/
            openapi.yml
          body: |
            ## 🤖 Auto-generated Update
            
            This PR updates the generated client based on the latest OpenAPI specification from Langfuse.
            
            ### Changes
            - Updated OpenAPI specification (if changed)
            - Updated generated code in `src/` from latest OpenAPI spec
            - Applied automatic formatting
            
            ### Validation
            CI checks will run on this PR (build, tests, clippy, fmt).
            
            To verify locally:
            - cargo build --all-features
            - cargo clippy --all-features --all-targets -- -D warnings
            - cargo test --all
            
            ---
            *This PR was automatically created by the nightly generation workflow.*
          # Use unified automated prefix for easier CI routing
          branch: automated/generate-client
          delete-branch: true
          labels: |
            dependencies
            automated
            automerge

      - name: Enable auto-merge for generated PR
        if: steps.check_changes.outputs.has_changes == 'true' && steps.cpr.outputs.pull-request-number != ''
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
        run: |
          gh pr merge "${{ steps.cpr.outputs.pull-request-number }}" --auto --rebase --delete-branch

      # No PAT fallback; fail early if token is missing
      - name: Assert App token present
        run: |
          if [ -z "${{ steps.app-token.outputs.token }}" ]; then
            echo "GitHub App token missing. Ensure BOT_APP_ID and BOT_PRIVATE_KEY are configured." >&2
            exit 1
          fi

      - name: Update existing PR branch from main
        uses: actions/github-script@v8
        with:
          github-token: ${{ steps.app-token.outputs.token }}
          script: |
            const { owner, repo } = context.repo;
            const head = 'automated/generate-client';
            const prs = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', base: 'main', head: `${owner}:${head}` });
            if (!prs.length) {
              core.info('No open PR for automated/generate-client.');
              return;
            }
            const number = prs[0].number;
            core.info(`Updating PR #${number} from base main...`);
            try {
              await github.rest.pulls.updateBranch({ owner, repo, pull_number: number });
              core.info('Branch update triggered.');
            } catch (e) {
              core.warning(`Update not needed or failed: ${e.message}`);
            }

  keepalive:
    runs-on: ubuntu-latest
    steps:
      - name: Keepalive Workflow
        uses: actions/github-script@v8
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            // This step ensures the workflow stays active even during periods of inactivity
            // GitHub disables scheduled workflows after 60 days of repository inactivity
            
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const workflow_id = 'generate-client.yml';
            
            // Get the workflow
            const workflow = await github.rest.actions.getWorkflow({
              owner,
              repo,
              workflow_id
            });
            
            console.log(`Workflow ${workflow.data.name} is ${workflow.data.state}`);
            
            // If the workflow is disabled, re-enable it
            if (workflow.data.state === 'disabled_inactivity') {
              await github.rest.actions.enableWorkflow({
                owner,
                repo,
                workflow_id
              });
              console.log('Workflow re-enabled');
            }
            
            // Log the last run to show activity
            const runs = await github.rest.actions.listWorkflowRuns({
              owner,
              repo,
              workflow_id,
              per_page: 1
            });
            
            if (runs.data.workflow_runs.length > 0) {
              const lastRun = runs.data.workflow_runs[0];
              console.log(`Last run: ${lastRun.created_at} - Status: ${lastRun.status}`);
            }