Skip to content
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,16 @@ go to the [Gemini Assistant workflow documentation](./examples/workflows/gemini-

- <a name="__input_upload_artifacts"></a><a href="#user-content-__input_upload_artifacts"><code>upload_artifacts</code></a>: _(Optional, default: `false`)_ Whether to upload artifacts to the github action.

- <a name="__input_output_to_file"></a><a href="#user-content-__input_output_to_file"><code>output_to_file</code></a>: _(Optional, default: `false`)_ When true, redirect all output to files and return file paths as step outputs instead of content. Useful when gemini_debug is true to avoid exceeding GitHub Actions output limits.

- <a name="__input_use_pnpm"></a><a href="#user-content-__input_use_pnpm"><code>use_pnpm</code></a>: _(Optional, default: `false`)_ Whether or not to use pnpm instead of npm to install gemini-cli

- <a name="__input_workflow_name"></a><a href="#user-content-__input_workflow_name"><code>workflow_name</code></a>: _(Optional, default: `${{ github.workflow }}`)_ The GitHub workflow name, used for telemetry purposes.

- <a name="__input_github_pr_number"></a><a href="#user-content-__input_github_pr_number"><code>github_pr_number</code></a>: _(Optional, default: `${{ github.event.pull_request.number }}`)_ The Pull Request number the CLI is operating on. Defaults to the event payload.

- <a name="__input_github_issue_number"></a><a href="#user-content-__input_github_issue_number"><code>github_issue_number</code></a>: _(Optional, default: `${{ github.event.issue.number }}`)_ The Issue number (or comma-separated list of issue numbers) the CLI is operating on. Defaults to the event payload.


<!-- END_AUTOGEN_INPUTS -->
<!-- prettier-ignore-end -->
Expand All @@ -227,6 +233,10 @@ go to the [Gemini Assistant workflow documentation](./examples/workflows/gemini-

- <a name="__output_error"></a><a href="#user-content-__output_error"><code>error</code></a>: The error output from the Gemini CLI execution, if any.

- <a name="__output_output_mode"></a><a href="#user-content-__output_output_mode"><code>output_mode</code></a>: Output mode used: "content" (default) or "file".

- <a name="__output_artifacts_dir"></a><a href="#user-content-__output_artifacts_dir"><code>artifacts_dir</code></a>: Path to gemini-artifacts/ directory containing stdout.log, stderr.log, telemetry.log.


<!-- END_AUTOGEN_OUTPUTS -->
<!-- prettier-ignore-end -->
Expand Down
114 changes: 80 additions & 34 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ inputs:
description: 'Whether to upload artifacts to the github action.'
required: false
default: 'false'
output_to_file:
description: 'When true, redirect all output to files and return file paths as step outputs instead of content. Useful when gemini_debug is true to avoid exceeding GitHub Actions output limits.'
required: false
default: 'false'
use_pnpm:
description: 'Whether or not to use pnpm instead of npm to install gemini-cli'
required: false
Expand All @@ -107,6 +111,12 @@ outputs:
error:
description: 'The error output from the Gemini CLI execution, if any.'
value: '${{ steps.gemini_run.outputs.gemini_errors }}'
output_mode:
description: 'Output mode used: "content" (default) or "file".'
value: '${{ steps.gemini_run.outputs.output_mode }}'
artifacts_dir:
description: 'Path to gemini-artifacts/ directory containing stdout.log, stderr.log, telemetry.log.'
value: '${{ steps.gemini_run.outputs.artifacts_dir }}'

runs:
using: 'composite'
Expand Down Expand Up @@ -301,12 +311,23 @@ runs:
# Keep track of whether we've failed
FAILED=false

# Determine debug flag
DEBUG_FLAG=""
if [[ "${GEMINI_DEBUG}" = true ]]; then
DEBUG_FLAG="--debug"
fi

# Run Gemini CLI with the provided prompt, using JSON output format
# We capture stdout (JSON) to TEMP_STDOUT and stderr to TEMP_STDERR
if [[ "${GEMINI_DEBUG}" = true ]]; then
if [[ "${OUTPUT_TO_FILE}" = true ]]; then
echo "::notice::Gemini CLI output redirected to files (gemini-artifacts/)"
if ! gemini ${DEBUG_FLAG} --yolo --prompt "${PROMPT}" --output-format json 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then
FAILED=true
fi
elif [[ "${GEMINI_DEBUG}" = true ]]; then
echo "::warning::Gemini CLI debug logging is enabled. This will stream responses, which could reveal sensitive information if processed with untrusted inputs."
echo "::: Start Gemini CLI STDOUT :::"
if ! gemini --debug --yolo --prompt "${PROMPT}" --output-format json 2> >(tee "${TEMP_STDERR}" >&2) | tee "${TEMP_STDOUT}"; then
if ! gemini ${DEBUG_FLAG} --yolo --prompt "${PROMPT}" --output-format json 2> >(tee "${TEMP_STDERR}" >&2) | tee "${TEMP_STDOUT}"; then
FAILED=true
fi
# Wait for async stderr logging to complete. This is because process substitution in Bash is async so let tee finish writing to ${TEMP_STDERR}
Expand Down Expand Up @@ -349,23 +370,38 @@ runs:
fi


# Set the captured response as a step output, supporting multiline
echo "gemini_response<<EOF" >> "${GITHUB_OUTPUT}"
if [[ -n "${RESPONSE}" ]]; then
echo "${RESPONSE}" >> "${GITHUB_OUTPUT}"
else
cat "${TEMP_STDOUT}" >> "${GITHUB_OUTPUT}"
fi
echo "EOF" >> "${GITHUB_OUTPUT}"
ARTIFACTS_DIR="$(pwd)/gemini-artifacts"
echo "artifacts_dir=${ARTIFACTS_DIR}" >> "${GITHUB_OUTPUT}"

# Set the captured errors as a step output, supporting multiline
echo "gemini_errors<<EOF" >> "${GITHUB_OUTPUT}"
if [[ -n "${ERROR_JSON}" ]]; then
echo "${ERROR_JSON}" >> "${GITHUB_OUTPUT}"
if [[ "${OUTPUT_TO_FILE}" = true ]]; then
echo "output_mode=file" >> "${GITHUB_OUTPUT}"
# Return file paths instead of content
echo "gemini_response<<EOF" >> "${GITHUB_OUTPUT}"
echo "${ARTIFACTS_DIR}/stdout.log" >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
echo "gemini_errors<<EOF" >> "${GITHUB_OUTPUT}"
echo "${ARTIFACTS_DIR}/stderr.log" >> "${GITHUB_OUTPUT}"
echo "EOF" >> "${GITHUB_OUTPUT}"
else
cat "${TEMP_STDERR}" >> "${GITHUB_OUTPUT}"
echo "output_mode=content" >> "${GITHUB_OUTPUT}"
# Set the captured response as a step output, supporting multiline
echo "gemini_response<<EOF" >> "${GITHUB_OUTPUT}"
if [[ -n "${RESPONSE}" ]]; then
echo "${RESPONSE}" >> "${GITHUB_OUTPUT}"
else
cat "${TEMP_STDOUT}" >> "${GITHUB_OUTPUT}"
fi
echo "EOF" >> "${GITHUB_OUTPUT}"

# Set the captured errors as a step output, supporting multiline
echo "gemini_errors<<EOF" >> "${GITHUB_OUTPUT}"
if [[ -n "${ERROR_JSON}" ]]; then
echo "${ERROR_JSON}" >> "${GITHUB_OUTPUT}"
else
cat "${TEMP_STDERR}" >> "${GITHUB_OUTPUT}"
fi
echo "EOF" >> "${GITHUB_OUTPUT}"
fi
echo "EOF" >> "${GITHUB_OUTPUT}"

# Generate Job Summary
if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then
Expand All @@ -378,26 +414,35 @@ runs:
echo "${PROMPT}"
echo "\`\`\`"
echo
if [[ -n "${RESPONSE}" ]]; then
echo "#### Response"
echo
echo "${RESPONSE}"
echo
fi
if [[ -n "${ERROR_JSON}" ]]; then
echo "#### Error"
echo
echo "\`\`\`json"
echo "${ERROR_JSON}"
echo "\`\`\`"
echo
elif [[ "${FAILED}" == "true" ]]; then
echo "#### Error Output"
if [[ "${OUTPUT_TO_FILE}" = true ]]; then
echo "#### Output (file mode)"
echo
echo "\`\`\`"
cat "${TEMP_STDERR}"
echo "\`\`\`"
echo "Output redirected to files:"
echo "- stdout.log ($(wc -c < "${TEMP_STDOUT}" | xargs) bytes)"
echo "- stderr.log ($(wc -c < "${TEMP_STDERR}" | xargs) bytes)"
echo
else
if [[ -n "${RESPONSE}" ]]; then
echo "#### Response"
echo
echo "${RESPONSE}"
echo
fi
if [[ -n "${ERROR_JSON}" ]]; then
echo "#### Error"
echo
echo "\`\`\`json"
echo "${ERROR_JSON}"
echo "\`\`\`"
echo
elif [[ "${FAILED}" == "true" ]]; then
echo "#### Error Output"
echo
echo "\`\`\`"
cat "${TEMP_STDERR}"
echo "\`\`\`"
echo
fi
fi
} >> "${GITHUB_STEP_SUMMARY}"
fi
Expand All @@ -415,6 +460,7 @@ runs:
fi
env:
GEMINI_DEBUG: '${{ fromJSON(inputs.gemini_debug || false) }}'
OUTPUT_TO_FILE: '${{ fromJSON(inputs.output_to_file || false) }}'
GEMINI_API_KEY: '${{ inputs.gemini_api_key }}'
SURFACE: 'GitHub'
GOOGLE_CLOUD_PROJECT: '${{ inputs.gcp_project_id }}'
Expand Down