rusty-bubbletea 2.0.8

Cleanroom Rust port of Charmbracelet's Bubble Tea (v2.0.8) TUI Elm architecture framework
Documentation
name: Publish to Crates.io

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

permissions:
  contents: write

jobs:
  publish:
    name: Publish Crate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - name: Verify version and tag match upstream
        run: scripts/verify_upstream_version.sh "$GITHUB_REF_NAME"
      - name: Configure shared Cargo cache
        run: |
          # The runner image pre-sets CARGO_HOME=$HOME/.cargo; drop the
          # ambient value so the shared-cache defaults apply (the resolver
          # rejects it as an uncontained override otherwise).
          unset CARGO_HOME
          . scripts/cargo-env.sh
          configure_shared_cargo_cache_environment
          {
            echo "CARGO_SHARED_CACHE_DIRECTORY=$CARGO_SHARED_CACHE_DIRECTORY"
            echo "CARGO_HOME=$CARGO_HOME"
            echo "CARGO_TARGET_DIR=$CARGO_TARGET_DIR"
            echo "CARGO_BUILD_BUILD_DIR=$CARGO_BUILD_BUILD_DIR"
            echo "CARGO_INSTALL_ROOT=$CARGO_INSTALL_ROOT"
          } >> "$GITHUB_ENV"
      - name: Test shared Cargo cache env
        run: scripts/test-cargo-env.sh
      - uses: actions/setup-go@v5
        with:
          go-version: 'stable'
      - name: Fetch upstream Go source (pinned)
        run: |
          git clone --quiet https://github.com/charmbracelet/bubbletea.git upstream-go
          cd upstream-go && git checkout --quiet v2.0.8
      - name: Fetch sibling rusty-bubbles (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-bubbles
          path: siblings/rusty-bubbles
          ref: dev
      - name: Fetch sibling rusty-colorprofile (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-colorprofile
          path: siblings/rusty-colorprofile
          ref: dev
      - name: Fetch sibling rusty-lipgloss (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-lipgloss
          path: siblings/rusty-lipgloss
          ref: dev
      - name: Fetch sibling rusty-testkit (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-testkit
          path: siblings/rusty-testkit
          ref: dev
      - name: Fetch sibling rusty-ultraviolet (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-ultraviolet
          path: siblings/rusty-ultraviolet
          ref: dev
      - name: Fetch sibling rusty-x-ansi (pinned)
        uses: actions/checkout@v4
        with:
          repository: coderbants/rusty-x-ansi
          path: siblings/rusty-x-ansi
          ref: dev
      - name: Place sibling crates
        run: |
          mkdir -p ../siblings && true
          mv siblings/rusty-bubbles ../rusty-bubbles
          mv siblings/rusty-colorprofile ../rusty-colorprofile
          mv siblings/rusty-lipgloss ../rusty-lipgloss
          mv siblings/rusty-testkit ../rusty-testkit
          mv siblings/rusty-ultraviolet ../rusty-ultraviolet
          mv siblings/rusty-x-ansi ../rusty-x-ansi
      - name: Format
        run: cargo fmt --all --check
      - name: Lint
        run: cargo clippy --all-targets -- -D warnings
      - name: Build
        run: cargo build --all-targets
      - name: Docgen
        run: cargo doc --no-deps
      - name: Test (all targets, all integration tests)
        run: cargo test --all-targets -- --test-threads=1
      - name: Prepare e2e fixtures
        run: |
          # The file_picker spec expects the macOS-style home folders that
          # both the Go and Rust examples list from $HOME.
          mkdir -p "$HOME/Applications" "$HOME/Documents"
      - name: Example E2E sweep (upstream Go vs Rust)
        run: ./scripts/e2e_examples.sh
      - name: Verify example parity (upstream Go vs Rust)
        run: ./scripts/verify_examples.sh
      - name: Create GitHub Release
        if: startsWith(github.ref, 'refs/tags/v')
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
            echo "Release $GITHUB_REF_NAME already exists; skipping."
          else
            gh release create "$GITHUB_REF_NAME" --generate-notes
          fi
      - name: Upload source to GitHub Release
        if: startsWith(github.ref, 'refs/tags/v')
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          src="${GITHUB_REPOSITORY##*/}-$GITHUB_REF_NAME.tar.gz"
          # Keep the archive out of the repo working tree so `cargo publish`
          # sees a clean checkout.
          git archive --format=tar.gz -o "$RUNNER_TEMP/$src" HEAD
          gh release upload "$GITHUB_REF_NAME" "$RUNNER_TEMP/$src" --clobber
      # Releases are tag-gated: only pushes of a v* tag publish. crates.io
      # rejects re-publishing an existing version, so the version-bump gate
      # in ci.yml keeps every release on a fresh, unreleased version.
      - name: Publish to crates.io
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          if [ -n "${CARGO_REGISTRY_TOKEN}" ]; then
            # Dev-dependencies are not part of the published crate, but
            # `cargo publish` resolves them anyway; drop them from the
            # packaging manifest so sibling dev-deps (which may be
            # unpublished or cyclically depend on this crate) can't block
            # the upload. The published crate is unaffected.
            awk '/^\[dev-dependencies\]/ { in_dev=1 } /^\[/ && !/^\[dev-dependencies\]/ { in_dev=0 } !(in_dev && /^rusty-/) { print }' Cargo.toml > Cargo.toml.publish
            mv Cargo.toml.publish Cargo.toml
            # --no-verify: the verify build resolves dependencies from the
            # registry, but ultraviolet's dev-dependency on lipgloss and
            # lipgloss's dependency on ultraviolet form a cycle; the full
            # gates (build, clippy, tests) already ran above.
            cargo publish --token "${CARGO_REGISTRY_TOKEN}" --no-verify --allow-dirty
            git checkout -- Cargo.toml
          else
            echo "No CARGO_REGISTRY_TOKEN secret; skipping crates.io publish."
          fi