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 }}
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 }}
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::"