git-iris 2.0.8

AI-powered Git workflow assistant for smart commits, code reviews, changelogs, and release notes
Documentation
name: "Git-Iris Action"
description: "AI agent that crafts perfect Git artifacts - release notes, changelogs, and more"
author: "hyperb1iss"
branding:
  icon: "git-commit"
  color: "purple"

inputs:
  command:
    description: "Command to run: release-notes, changelog"
    required: false
    default: "release-notes"
  from:
    description: "Starting Git reference (tag, commit, or branch)"
    required: true
  to:
    description: "Ending Git reference (defaults to HEAD)"
    required: false
    default: "HEAD"
  provider:
    description: "LLM provider (openai, anthropic, google)"
    required: false
    default: "openai"
  model:
    description: "Model to use (provider-specific)"
    required: false
  api-key:
    description: "API key for the LLM provider"
    required: true
  output-file:
    description: "File path to write output (optional)"
    required: false
  version-name:
    description: "Explicit version name to use"
    required: false
  custom-instructions:
    description: "Custom instructions for generation"
    required: false
  update-file:
    description: "Update the target file using native git-iris update behavior"
    required: false
    default: "false"
  version:
    description: "Git-Iris version to use (defaults to latest)"
    required: false
    default: "latest"
  build-from-source:
    description: "Build from source instead of downloading binary"
    required: false
    default: "false"
  binary-path:
    description: "Path to pre-built git-iris binary (skips download and build)"
    required: false

outputs:
  content:
    description: "Generated content"
    value: ${{ steps.generate.outputs.content }}
  output-file:
    description: "Path to the output file (if specified)"
    value: ${{ steps.generate.outputs.output_file }}
  # Backwards compatibility aliases
  release-notes:
    description: "Generated content (alias for backwards compatibility)"
    value: ${{ steps.generate.outputs.content }}
  release-notes-file:
    description: "Output file path (alias for backwards compatibility)"
    value: ${{ steps.generate.outputs.output_file }}

runs:
  using: "composite"
  steps:
    - name: Determine platform
      id: platform
      shell: bash
      run: |
        case "${{ runner.os }}-${{ runner.arch }}" in
          Linux-X64)
            echo "artifact=git-iris-linux-amd64" >> $GITHUB_OUTPUT
            echo "binary=git-iris" >> $GITHUB_OUTPUT
            ;;
          Linux-ARM64)
            echo "artifact=git-iris-linux-arm64" >> $GITHUB_OUTPUT
            echo "binary=git-iris" >> $GITHUB_OUTPUT
            ;;
          macOS-ARM64)
            echo "artifact=git-iris-macos-arm64" >> $GITHUB_OUTPUT
            echo "binary=git-iris" >> $GITHUB_OUTPUT
            ;;
          macOS-X64)
            echo "::error::Unsupported platform: macOS-X64 (no published x64 macOS binary)"
            exit 1
            ;;
          Windows-X64)
            echo "artifact=git-iris-windows-gnu" >> $GITHUB_OUTPUT
            echo "binary=git-iris.exe" >> $GITHUB_OUTPUT
            ;;
          *)
            echo "::error::Unsupported platform: ${{ runner.os }}-${{ runner.arch }}"
            exit 1
            ;;
        esac

    - name: Use pre-built binary
      if: inputs.binary-path != ''
      shell: bash
      run: |
        echo "Using pre-built binary: ${{ inputs.binary-path }}"
        echo "GIT_IRIS_BIN=${{ inputs.binary-path }}" >> $GITHUB_ENV

    - name: Install Rust (for build-from-source)
      if: inputs.binary-path == '' && inputs.build-from-source == 'true'
      uses: dtolnay/rust-toolchain@stable

    - name: Rust cache (for build-from-source)
      if: inputs.binary-path == '' && inputs.build-from-source == 'true'
      uses: Swatinem/rust-cache@v2

    - name: Download git-iris binary
      if: inputs.binary-path == '' && inputs.build-from-source != 'true'
      shell: bash
      env:
        GH_TOKEN: ${{ github.token }}
      run: |
        set -euo pipefail

        echo "::group::Downloading git-iris"

        INSTALL_DIR="$RUNNER_TEMP/git-iris-bin"
        DOWNLOAD_DIR="$RUNNER_TEMP/git-iris-download-${RANDOM}"
        mkdir -p "$INSTALL_DIR" "$DOWNLOAD_DIR"

        if [ "${{ inputs.version }}" = "latest" ]; then
          VERSION=$(gh release view --repo hyperb1iss/git-iris --json tagName -q '.tagName')
        else
          VERSION="${{ inputs.version }}"
        fi

        echo "Downloading git-iris $VERSION for ${{ steps.platform.outputs.artifact }}"

        gh release download "$VERSION" \
          --repo hyperb1iss/git-iris \
          --pattern "${{ steps.platform.outputs.artifact }}*" \
          --dir "$DOWNLOAD_DIR"

        shopt -s nullglob
        matches=("$DOWNLOAD_DIR"/${{ steps.platform.outputs.artifact }}*)
        shopt -u nullglob

        if [ "${#matches[@]}" -ne 1 ]; then
          echo "::error::Expected exactly one downloaded artifact, found ${#matches[@]}"
          ls -la "$DOWNLOAD_DIR"
          exit 1
        fi

        TARGET_PATH="$INSTALL_DIR/${{ steps.platform.outputs.binary }}"
        cp "${matches[0]}" "$TARGET_PATH"
        chmod +x "$TARGET_PATH" || true

        echo "$INSTALL_DIR" >> "$GITHUB_PATH"
        echo "GIT_IRIS_BIN=$TARGET_PATH" >> "$GITHUB_ENV"

        echo "git-iris installed successfully"
        "$TARGET_PATH" --version
        echo "::endgroup::"

    - name: Build git-iris from source
      if: inputs.binary-path == '' && inputs.build-from-source == 'true'
      shell: bash
      run: |
        set -euo pipefail

        echo "::group::Building git-iris from source"
        INSTALL_DIR="$RUNNER_TEMP/git-iris-bin"
        TARGET_PATH="$INSTALL_DIR/${{ steps.platform.outputs.binary }}"

        mkdir -p "$INSTALL_DIR"
        cargo build --release --locked
        cp "./target/release/${{ steps.platform.outputs.binary }}" "$TARGET_PATH"

        echo "$INSTALL_DIR" >> "$GITHUB_PATH"
        echo "GIT_IRIS_BIN=$TARGET_PATH" >> "$GITHUB_ENV"
        "$TARGET_PATH" --version
        echo "::endgroup::"

    - name: Generate content
      id: generate
      shell: bash
      env:
        ACTION_API_KEY: ${{ inputs.api-key }}
        IRIS_COMMAND: ${{ inputs.command }}
        IRIS_FROM: ${{ inputs.from }}
        IRIS_TO: ${{ inputs.to }}
        IRIS_PROVIDER_INPUT: ${{ inputs.provider }}
        IRIS_MODEL: ${{ inputs.model }}
        IRIS_INSTRUCTIONS: ${{ inputs.custom-instructions }}
        IRIS_VERSION_NAME: ${{ inputs.version-name }}
        IRIS_OUTPUT_FILE: ${{ inputs.output-file }}
        IRIS_UPDATE_FILE: ${{ inputs.update-file }}
        # Ensure clean markdown output - no colors or formatting
        NO_COLOR: "1"
        TERM: dumb
        CLICOLOR: "0"
        CLICOLOR_FORCE: "0"
      run: |
        set -euo pipefail

        echo "::group::Running git-iris $IRIS_COMMAND"

        GIT_IRIS="${GIT_IRIS_BIN:-git-iris}"
        COMMAND="$IRIS_COMMAND"

        case "$COMMAND" in
          release-notes|changelog) ;;
          *)
            echo "::error::Unsupported command: $COMMAND"
            exit 1
            ;;
        esac

        case "${IRIS_PROVIDER_INPUT,,}" in
          openai)
            IRIS_PROVIDER="openai"
            export OPENAI_API_KEY="$ACTION_API_KEY"
            ;;
          anthropic|claude)
            IRIS_PROVIDER="anthropic"
            export ANTHROPIC_API_KEY="$ACTION_API_KEY"
            ;;
          google|gemini)
            IRIS_PROVIDER="google"
            export GOOGLE_API_KEY="$ACTION_API_KEY"
            ;;
          *)
            echo "::error::Unsupported provider: $IRIS_PROVIDER_INPUT"
            exit 1
            ;;
        esac

        echo "Provider: $IRIS_PROVIDER"
        if [ -n "${IRIS_MODEL:-}" ]; then
          echo "Model: $IRIS_MODEL"
        else
          echo "Model: provider default"
        fi

        # Build the command as an argv array so provider/model/ref values are passed literally.
        cmd=(
          "$GIT_IRIS"
          "$COMMAND"
          "--from" "$IRIS_FROM"
          "--to" "$IRIS_TO"
          "--provider" "$IRIS_PROVIDER"
          "--raw"
          "--quiet"
        )

        # Add version name if specified
        if [ -n "${IRIS_VERSION_NAME:-}" ]; then
          cmd+=("--version-name" "$IRIS_VERSION_NAME")
        fi

        # Add model if specified
        if [ -n "${IRIS_MODEL:-}" ]; then
          cmd+=("--model" "$IRIS_MODEL")
        fi

        # Add custom instructions if specified
        if [ -n "${IRIS_INSTRUCTIONS:-}" ]; then
          cmd+=("--instructions" "$IRIS_INSTRUCTIONS")
        fi

        if [ "$IRIS_UPDATE_FILE" = "true" ]; then
          cmd+=("--update")

          if [ -n "${IRIS_OUTPUT_FILE:-}" ]; then
            cmd+=("--file" "$IRIS_OUTPUT_FILE")
          fi
        fi

        # Execute and capture output
        CONTENT="$("${cmd[@]}")"

        # Handle multiline output for GitHub Actions
        DELIMITER="GIT_IRIS_$(date +%s%N)_$$"
        {
          echo "content<<$DELIMITER"
          printf '%s\n' "$CONTENT"
          echo "$DELIMITER"
        } >> "$GITHUB_OUTPUT"

        if [ "$IRIS_UPDATE_FILE" = "true" ]; then
          OUTPUT_FILE="$IRIS_OUTPUT_FILE"
          if [ -z "${OUTPUT_FILE:-}" ]; then
            if [ "$COMMAND" = "changelog" ]; then
              OUTPUT_FILE="CHANGELOG.md"
            else
              OUTPUT_FILE="RELEASE_NOTES.md"
            fi
          fi

          echo "output_file=$OUTPUT_FILE" >> "$GITHUB_OUTPUT"
          echo "Content written to $OUTPUT_FILE"
        elif [ -n "${IRIS_OUTPUT_FILE:-}" ]; then
          OUTPUT_FILE="$IRIS_OUTPUT_FILE"
          mkdir -p "$(dirname "$OUTPUT_FILE")"
          printf '%s\n' "$CONTENT" > "$OUTPUT_FILE"

          echo "output_file=$OUTPUT_FILE" >> "$GITHUB_OUTPUT"
          echo "Content written to $OUTPUT_FILE"
        fi

        echo "::endgroup::"

        # Print preview
        echo "::group::Generated Content Preview"
        STOP_COMMAND="git_iris_stop_$(date +%s%N)"
        echo "::stop-commands::$STOP_COMMAND"
        printf '%s\n' "$CONTENT"
        echo "::$STOP_COMMAND::"
        echo "::endgroup::"