JSPM

team-roulette

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 10
  • Score
    100M100P100Q8098F
  • License MIT

Fair CODEOWNERS-based reviewer roulette with CLI and web app

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (team-roulette) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    team-roulette

    Pick a reviewer from CODEOWNERS — locally, from a public owner/repo, or in the browser.

    Web app: luandev.github.io/team-roulette/play · Source: github.com/luandev/team-roulette

    Requires Node.js 18+ for the CLI. Zero runtime dependencies.

    CLI

    npm install -g team-roulette
    
    team-roulette owner/repo                 # pick one owner
    team-roulette owner/repo path/to/file    # match a path
    team-roulette -m owner/repo              # pick with animation
    team-roulette --list owner/repo          # shuffle all owners
    team-roulette -j owner/repo              # JSON output

    Web

    1. Open the web app — enter owner/repo, a raw URL, or upload CODEOWNERS
    2. Path defaults to *; choose pick, list, or sort
    3. Run — full-screen result (memory in localStorage)

    Public repos load over HTTPS from GitHub. No account, no backend.

    The landing page replays CLI demos (asciinema .cast files) in the hero — click examples or use-case cards to switch recordings.


    Install

    # From npm (when published)
    npm install -g team-roulette
    
    # From source
    git clone https://github.com/luandev/team-roulette
    cd team-roulette && npm install && npm run build
    npm link

    Web (local)

    npm run dev:web    # http://localhost:5173/team-roulette/play
    npm run build:casts  # regenerate web/public/casts/*.cast from CLI renderers
    npm run build:web  # build:casts + web/dist/

    Deploy: push to main.github/workflows/deploy-pages.yml publishes web/dist to GitHub Pages.


    Use cases

    Scenario Command
    PR reviewer — who reviews this path? team-roulette owner/repo path/to/file.ts
    Standup order — shuffle speakers team-roulette --list owner/repo
    On-call / incident — pick one platform owner team-roulette kubernetes/kubernetes pkg/
    Driver vs navigator — one of several owners team-roulette -m vercel/next.js
    Ownership audit — who matches most rules? team-roulette --sort frequency elastic/kibana
    History fairness — who was picked least? team-roulette --sort history owner/repo
    CI / automation team-roulette -j owner/repo
    Workshop icebreaker team-roulette -m apple/swift
    Private / local file Upload CODEOWNERS in the web app or run CLI in repo root

    GitHub repo shorthand

    Pass owner/repo as the first argument. CODEOWNERS is fetched over pure HTTPS from raw.githubusercontent.com (no token needed for public repos). Branches tried: main, then master.

    team-roulette microsoft/vscode
    team-roulette grafana/grafana
    team-roulette microsoft/vscode src/vs/workbench/
    Behavior Default
    Match path * (whole repo) when only owner/repo is given
    Output Selected: @handle or Selected: @org/team [team] (single pick, no animation)
    No global * rule Falls back to all owners in the file

    Add -m to enable pick animations (-m alone uses slot-machine; -m glitch for a specific style). If the token after -m looks like owner/repo, it is treated as the repo, not an animation name. Add --list to shuffle and display everyone.

    Repos without GitHub CODEOWNERS (e.g. kubernetes/kubernetes) are loaded from root OWNERS + OWNERS_ALIASES (Kubernetes/Prow format).


    Owner types

    CODEOWNERS and Kubernetes OWNERS entries are classified automatically:

    Kind Example Label
    User @alice (none)
    Team @grafana/grafana-backend-services-squad [team]
    Email team@example.com [email]

    Picking a team means “this GitHub team owns the review” — not a random team member. Use --users-only to exclude teams from the pool, or --teams-only to pick only teams.

    team-roulette grafana/grafana              # may pick @grafana/… [team]
    team-roulette --users-only grafana/grafana # only @username handles
    team-roulette kubernetes/kubernetes        # uses root OWNERS (not CODEOWNERS)

    The web app has an Owner pool filter (All / Users only / Teams only) with the same behavior.


    Single selection

    Picks one owner using fairness memory (unless --no-memory).

    # Local CODEOWNERS (walks up for .github/CODEOWNERS)
    team-roulette src/auth/login.ts
    team-roulette .
    
    # Remote shorthand
    team-roulette microsoft/vscode src/vs/
    
    # Animations
    team-roulette -m slot-machine src/auth/
    team-roulette -m glitch microsoft/vscode
    team-roulette -m eliminator grafana/grafana
    
    # Pure random (ignores history)
    team-roulette --no-memory src/auth/
    
    # Owner filters
    team-roulette --users-only grafana/grafana
    team-roulette --teams-only grafana/grafana
    
    # JSON
    team-roulette -j src/auth/login.ts
    # { "selected": "@alice", "selectedKind": "user", "candidateKinds": {...}, ... }

    Pick animation modes (-m):

    Mode Description
    slot-machine Three-row reel with deceleration (default when -m used)
    glitch Characters lock in left-to-right
    eliminator Names struck through until one remains

    List mode (--list / -l)

    Shuffles all matching owners into a random order and reveals them with animation (no fairness pick — everyone is shown).

    team-roulette --list microsoft/vscode
    team-roulette -l src/auth/
    team-roulette --list microsoft/vscode src/vs/workbench/
    
    # List animations (default: cascade if -m omitted)
    team-roulette --list -m slot-machine elastic/kibana
    team-roulette --list -m glitch microsoft/vscode
    team-roulette --list -m eliminator src/auth/
    team-roulette --list -m cascade microsoft/vscode
    
    # JSON (shuffled order in "selected" array)
    team-roulette -j --list microsoft/vscode
    # { "selected": ["@bob", "@alice", ...], "list": true, ... }

    List animation modes (--list -m):

    Mode Description
    cascade Rows reveal top-to-bottom (default for --list)
    slot-machine Rows swap rapidly then lock in
    glitch Each row decrypts in sequence
    eliminator Live reorder with swap highlights

    Analytical sort (--sort)

    No animation, no random pick — prints an ordered table for inspection.

    team-roulette --sort alpha src/auth/
    team-roulette --sort frequency microsoft/vscode
    team-roulette --sort history src/auth/
    Type Order
    alpha Alphabetical
    frequency Most CODEOWNERS rule matches first
    history Least often picked first (memory log)

    Explicit sources (-s / --source)

    # GitHub API (supports private repos with GITHUB_TOKEN)
    team-roulette --source github:microsoft/vscode src/vs/
    
    # GitLab API
    team-roulette --source gitlab:gitlab-org/gitlab src/foo.rb
    
    # Direct HTTPS URL to a CODEOWNERS file
    team-roulette --source https://raw.githubusercontent.com/org/repo/main/.github/CODEOWNERS
    team-roulette --list --source https://raw.githubusercontent.com/org/repo/main/.github/CODEOWNERS

    JSON output (-j / --json)

    Always plain JSON, no ANSI. Field selected is used for all modes (agnostic naming):

    Mode selected list
    Single pick "@handle" false
    --list ["@a", "@b", ...] true

    Example:

    {
      "selected": "@joaomoreno",
      "candidates": ["@alice", "@bob"],
      "list": false,
      "repoKey": "github:microsoft/vscode",
      "path": "*",
      "mode": "slot-machine",
      "memory": true,
      "source": "microsoft/vscode"
    }

    Fairness memory

    Single-select mode stores history at:

    ~/.config/team-roulette/history.json

    (or $XDG_CONFIG_HOME/team-roulette/history.json)

    1. Excludes the last picked owner when multiple candidates exist
    2. Prefers owners with the lowest pick count in history
    3. Random tie-break

    --no-memory disables this. --list does not write to history.


    Environment variables

    Variable Purpose
    GITHUB_TOKEN Auth for --source github: (API path)
    GITLAB_TOKEN Auth for GitLab API
    NO_COLOR Disable ANSI colors
    XDG_CONFIG_HOME Override config directory

    All CLI flags

    -l, --list                  Shuffle & display all owners (animated)
    -s, --source <target>       github:owner/repo | gitlab:group/project | https://...
    -m, --mode <template>       Animation mode (pick or list)
    --no-memory                 Random single pick (no history)
    --sort <alpha|frequency|history>   Ordered table output
    -j, --json                  JSON output
    -h, --help
    -v, --version

    Adding animations

    Single pick — implement AnimationTemplate in src/animations/ and register in src/animations/registry.ts.

    List — implement ListAnimationTemplate in src/animations/list/ and register in src/animations/list-registry.ts.


    Development

    npm install
    npm test
    npm run build
    node dist/bin/team-roulette.js --list microsoft/vscode
    node dist/bin/team-roulette.js -j --list -m glitch microsoft/vscode

    Commits and releases

    This project uses Conventional Commits and semantic-release for automated semver and GitHub releases.

    feat: add new feature        → minor bump
    fix: patch bug               → patch bump
    feat!: breaking change       → major bump

    Examples: feat(web): add file picker, fix(cli): correct path matching

    npm publish (CI)

    Pushes to main run .github/workflows/release.yml, which publishes team-roulette to npm when there are releasable commits.

    GitHub secret: NPM_TOKEN — create at npmjs.com → Access Tokens:

    • Granular token: Packages → Read and Write for team-roulette (or all packages on first publish)
    • Classic token: type Automation (not Publish — that is for local login)

    Paste the token into Repository → Settings → Secrets → Actions → NPM_TOKEN. Re-run the failed Release workflow or push a fix: / feat: commit after updating the secret.

    npm install -g team-roulette
    team-roulette owner/repo

    License

    MIT