From 6fb331c42e0e658f669c50a4c5a82778b00a8146 Mon Sep 17 00:00:00 2001 From: Michal Szelag Date: Wed, 11 Mar 2026 15:25:13 -0400 Subject: [PATCH 1/4] feat: add file-based output mode to avoid exceeding GitHub Actions output limits Add `output_to_file` input that redirects all output to files and returns file paths as step outputs instead of content. When enabled with `gemini_debug: true`, debug output goes to files without console streaming, keeping GITHUB_OUTPUT well under the ~1MB platform limit. New outputs: `output_mode` (content/file) and `artifacts_dir` (path to gemini-artifacts/). Full backwards compatibility when not set. Ref: google-github-actions/run-gemini-cli#479 --- action.yml | 106 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/action.yml b/action.yml index 7eccaf14b..02e30b02d 100644 --- a/action.yml +++ b/action.yml @@ -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 @@ -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' @@ -303,7 +313,12 @@ runs: # 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 [[ "${GEMINI_DEBUG}" = true ]] && [[ "${OUTPUT_TO_FILE}" = true ]]; then + echo "::notice::Gemini CLI debug output redirected to files (gemini-artifacts/)" + if ! gemini --debug --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 @@ -349,23 +364,38 @@ runs: fi - # Set the captured response as a step output, supporting multiline - echo "gemini_response<> "${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<> "${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<> "${GITHUB_OUTPUT}" + echo "${ARTIFACTS_DIR}/stdout.log" >> "${GITHUB_OUTPUT}" + echo "EOF" >> "${GITHUB_OUTPUT}" + echo "gemini_errors<> "${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<> "${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<> "${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 @@ -378,26 +408,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 @@ -415,6 +454,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 }}' From badefcd68eb3d57d7f95b346691a5ea2ea1a8905 Mon Sep 17 00:00:00 2001 From: Michal Szelag Date: Wed, 11 Mar 2026 17:38:48 -0400 Subject: [PATCH 2/4] refactor: decouple output_to_file from gemini_debug Check output_to_file first, independently of debug mode. The debug flag only controls whether --debug is passed to gemini CLI. Also extract command args to avoid duplicating the gemini invocation. Ref: google-github-actions/run-gemini-cli#479 --- action.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/action.yml b/action.yml index 02e30b02d..1a428a7c3 100644 --- a/action.yml +++ b/action.yml @@ -311,24 +311,30 @@ runs: # Keep track of whether we've failed FAILED=false + # Build the base command arguments + GEMINI_ARGS="--yolo --prompt ${PROMPT} --output-format json" + if [[ "${GEMINI_DEBUG}" = true ]]; then + GEMINI_ARGS="--debug ${GEMINI_ARGS}" + 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 ]] && [[ "${OUTPUT_TO_FILE}" = true ]]; then - echo "::notice::Gemini CLI debug output redirected to files (gemini-artifacts/)" - if ! gemini --debug --yolo --prompt "${PROMPT}" --output-format json 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then + if [[ "${OUTPUT_TO_FILE}" = true ]]; then + echo "::notice::Gemini CLI output redirected to files (gemini-artifacts/)" + if ! gemini ${GEMINI_ARGS} 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 ${GEMINI_ARGS} 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} sleep 1 echo "::: End Gemini CLI STDOUT :::" else - if ! gemini --yolo --prompt "${PROMPT}" --output-format json 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then + if ! gemini ${GEMINI_ARGS} 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then FAILED=true fi fi From 8023d45c4807f7c973560e5c551acea18c6ec340 Mon Sep 17 00:00:00 2001 From: Michal Szelag Date: Wed, 11 Mar 2026 17:46:37 -0400 Subject: [PATCH 3/4] docs: regenerate README with new input and outputs Run `npm run docs` to update autogenerated sections with: - output_to_file input - output_mode and artifacts_dir outputs Ref: google-github-actions/run-gemini-cli#479 --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index cdb4c3e09..00748e426 100644 --- a/README.md +++ b/README.md @@ -190,10 +190,16 @@ go to the [Gemini Assistant workflow documentation](./examples/workflows/gemini- - upload_artifacts: _(Optional, default: `false`)_ Whether to upload artifacts to the github action. +- output_to_file: _(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. + - use_pnpm: _(Optional, default: `false`)_ Whether or not to use pnpm instead of npm to install gemini-cli - workflow_name: _(Optional, default: `${{ github.workflow }}`)_ The GitHub workflow name, used for telemetry purposes. +- github_pr_number: _(Optional, default: `${{ github.event.pull_request.number }}`)_ The Pull Request number the CLI is operating on. Defaults to the event payload. + +- github_issue_number: _(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. + @@ -207,6 +213,10 @@ go to the [Gemini Assistant workflow documentation](./examples/workflows/gemini- - error: The error output from the Gemini CLI execution, if any. +- output_mode: Output mode used: "content" (default) or "file". + +- artifacts_dir: Path to gemini-artifacts/ directory containing stdout.log, stderr.log, telemetry.log. + From 8d07671166f90d879aa1700d14aea0cd077cc052 Mon Sep 17 00:00:00 2001 From: Michal Szelag Date: Thu, 12 Mar 2026 06:18:56 -0400 Subject: [PATCH 4/4] fix: preserve prompt quoting in gemini CLI invocation The GEMINI_ARGS variable caused word-splitting on the multi-line PROMPT string, breaking the gemini CLI argument parsing. Use a separate DEBUG_FLAG variable instead and keep "${PROMPT}" quoted in each invocation. Ref: google-github-actions/run-gemini-cli#479 --- action.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/action.yml b/action.yml index 1a428a7c3..84fbd70bf 100644 --- a/action.yml +++ b/action.yml @@ -311,30 +311,30 @@ runs: # Keep track of whether we've failed FAILED=false - # Build the base command arguments - GEMINI_ARGS="--yolo --prompt ${PROMPT} --output-format json" + # Determine debug flag + DEBUG_FLAG="" if [[ "${GEMINI_DEBUG}" = true ]]; then - GEMINI_ARGS="--debug ${GEMINI_ARGS}" + 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 [[ "${OUTPUT_TO_FILE}" = true ]]; then echo "::notice::Gemini CLI output redirected to files (gemini-artifacts/)" - if ! gemini ${GEMINI_ARGS} 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then + 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 ${GEMINI_ARGS} 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} sleep 1 echo "::: End Gemini CLI STDOUT :::" else - if ! gemini ${GEMINI_ARGS} 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then + if ! gemini --yolo --prompt "${PROMPT}" --output-format json 2> "${TEMP_STDERR}" 1> "${TEMP_STDOUT}"; then FAILED=true fi fi