diff --git a/.github/workflows/gemini-issue-automated-triage.yml b/.github/workflows/gemini-issue-automated-triage.yml index f6feec3..03dea23 100644 --- a/.github/workflows/gemini-issue-automated-triage.yml +++ b/.github/workflows/gemini-issue-automated-triage.yml @@ -1,4 +1,4 @@ -name: Gemini Automated Issue Triage +name: 🏷️ Gemini Automated Issue Triage on: issues: @@ -18,20 +18,21 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout repository uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} - name: Run Gemini Issue Triage uses: ./ env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} ISSUE_TITLE: ${{ github.event.issue.title }} ISSUE_BODY: ${{ github.event.issue.body }} ISSUE_NUMBER: ${{ github.event.issue.number }} @@ -57,13 +58,14 @@ jobs: You are an issue triage assistant. Analyze the current GitHub issue and apply the most appropriate existing labels. Steps: - 1. Run: `gh label list --limit 100` to get all available labels. + 1. Run: `gh label list` to get all available labels. 2. Review the issue title and body provided in the environment variables. - 3. Select the most relevant labels from the existing labels, focusing on kind/*, area/*, and priority/*. + 3. Select the most relevant labels from the existing labels. If available, set labels that follow the `kind/*`, `area/*`, and `priority/*` patterns. 4. Apply the selected labels to this issue using: `gh issue edit ISSUE_NUMBER --add-label "label1,label2"` + 5. If the `status/needs-triage` label is present, remove it using: `gh issue edit ISSUE_NUMBER --remove-label "status/needs-triage"` Guidelines: - Only use labels that already exist in the repository. - Do not add comments or modify the issue content. - Triage only the current issue. - - Assign all applicable kind/*, area/*, and priority/* labels based on the issue content. + - Assign all applicable labels based on the issue content. diff --git a/.github/workflows/gemini-issue-scheduled-triage.yml b/.github/workflows/gemini-issue-scheduled-triage.yml index 6da9865..d9e7b0f 100644 --- a/.github/workflows/gemini-issue-scheduled-triage.yml +++ b/.github/workflows/gemini-issue-scheduled-triage.yml @@ -1,4 +1,4 @@ -name: Scheduled Issue Triage +name: 📋 Gemini Scheduled Issue Triage on: schedule: @@ -16,26 +16,36 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout repository uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} - name: Find untriaged issues id: find_issues env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} run: | + echo "🔍 Finding issues without labels..." NO_LABEL_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue no:label" --json number,title,body) - NEEDS_TRIAGE_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue label:\"status/needs-triage\"" --json number,title,body) - ISSUES=$(echo "$NO_LABEL_ISSUES" "$NEEDS_TRIAGE_ISSUES" | jq -c -s 'add | unique_by(.number)') + + echo "🏷️ Finding issues that need triage..." + NEED_TRIAGE_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue label:\"status/needs-triage\"" --json number,title,body) + + echo "🔄 Merging and deduplicating issues..." + ISSUES=$(echo "$NO_LABEL_ISSUES" "$NEED_TRIAGE_ISSUES" | jq -c -s 'add | unique_by(.number)') + + echo "📝 Setting output for GitHub Actions..." echo "issues_to_triage=$ISSUES" >> "$GITHUB_OUTPUT" + echo "✅ Found $(echo "$ISSUES" | jq 'length') issues to triage! 🎯" + - name: Run Gemini Issue Triage if: steps.find_issues.outputs.issues_to_triage != '[]' uses: ./ @@ -51,6 +61,7 @@ jobs: settings_json: | { "coreTools": [ + "run_shell_command(echo)", "run_shell_command(gh label list)", "run_shell_command(gh issue edit)", "run_shell_command(gh issue list)" @@ -65,12 +76,12 @@ jobs: You are an issue triage assistant. Analyze issues and apply appropriate labels. Steps: - 1. Run: `gh label list --limit 100` + 1. Run: `gh label list` 2. Check environment variable: $ISSUES_TO_TRIAGE (JSON array of issues) - 3. For each issue, apply labels: `gh issue edit ISSUE_NUMBER --add-label "label1,label2"` + 3. For each issue, apply labels: `gh issue edit ISSUE_NUMBER --add-label "label1,label2"`. If available, set labels that follow the `kind/*`, `area/*`, and `priority/*` patterns. + 4. For each issue, if the `status/needs-triage` label is present, remove it using: `gh issue edit ISSUE_NUMBER --remove-label "status/needs-triage"` Guidelines: - Only use existing repository labels - Do not add comments - Triage each issue independently - - Focus on: kind/*, area/*, priority/* labels diff --git a/.github/workflows/gemini-pr-review.yml b/.github/workflows/gemini-pr-review.yml index 580b4a7..f80550c 100644 --- a/.github/workflows/gemini-pr-review.yml +++ b/.github/workflows/gemini-pr-review.yml @@ -1,4 +1,4 @@ -name: Gemini PR Review +name: 🧐 Gemini Pull Request Review on: issue_comment: @@ -30,16 +30,16 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout PR code uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} - ref: ${{ github.event.pull_request.head.sha }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: Get PR details diff --git a/README.md b/README.md index 0545543..5de1e17 100644 --- a/README.md +++ b/README.md @@ -42,17 +42,12 @@ This action is configured via inputs in your workflow file. For detailed informa ## Authentication -This action uses the `gh` CLI to interact with the GitHub API. You'll need to provide it with a token that has the necessary permissions for your use case. +This action requires a GitHub token to interact with the GitHub API. You can authenticate in two ways: -When you create your GitHub App, you must grant it the correct permissions for your intended use cases. The permissions below are required for the provided example workflows to function correctly. +1. **Custom GitHub App (Recommended):** For the most secure and flexible authentication, we recommend creating a custom GitHub App. +2. **Default `GITHUB_TOKEN`:** For simpler use cases, the action can use the default `GITHUB_TOKEN` provided by the workflow. -- **Repository permissions:** - - **Contents**: `Read-only` - Allows the action to check out code and read repository files. - - **Issues**: `Read & write` - Allows the action to read issue details and then comment on or label them. - -**Important**: The permissions above are a baseline for the examples. If you create custom workflows that interact with the GitHub API in other ways (e.g., modifying projects, creating branches, managing deployments), you must update your GitHub App's permissions to grant the necessary access. Always follow the principle of least privilege, granting only the permissions your specific workflow requires. - -For more information on creating and using GitHub Apps, see the [documentation](https://docs.github.com/en/apps). +For a detailed guide on how to set up authentication, including creating a custom app and the required permissions, please see the [**Authentication documentation**](./docs/github-app.md). ## Observability with OpenTelemetry diff --git a/docs/configuration.md b/docs/configuration.md index cc45d1e..8820288 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2,6 +2,8 @@ You can customize the behavior of the Gemini CLI Action by using the available inputs in your GitHub workflow file. For advanced use cases, you can provide a JSON object to the `settings_json` input to control the underlying Gemini CLI. +For details on creating a custom GitHub App, see the [**GitHub App creation documentation**](./github-app.md). + ## Action Inputs ### `prompt` diff --git a/docs/github-app.md b/docs/github-app.md new file mode 100644 index 0000000..bac2670 --- /dev/null +++ b/docs/github-app.md @@ -0,0 +1,66 @@ +# Authenticating with a GitHub App + +This guide details the authentication methods for the Gemini CLI Action, ensuring it has the necessary permissions to interact with the GitHub API on your behalf. + +You can authenticate using one of two methods: +* **GitHub App (Recommended):** Provides the most secure and flexible approach by creating a dedicated app with specific permissions. +* **Default `GITHUB_TOKEN`:** A simpler method suitable for basic use cases, using the token automatically generated for each workflow run. + +## Using a GitHub App (Recommended) + +For optimal security and control, we strongly recommend creating a custom GitHub App. This method allows you to grant the action fine-grained permissions, limiting its access to only what is necessary. + +### Step 1: Create a New GitHub App + +1. Navigate to **GitHub Settings** > **[Developer settings](https://github.com/settings/developers)** > **[GitHub Apps](https://github.com/settings/apps)** and click **New GitHub App**. +2. **Complete the app registration:** + * **GitHub App name:** Give your app a unique and descriptive name (e.g., `MyOrg-Gemini-Assistant`). + * **Homepage URL:** Enter your organization's website or the URL of the repository where you'll use the action. +3. **Disable Webhooks:** Uncheck the **Active** checkbox under the "Webhooks" section. This action does not require webhook notifications. +4. **Set Repository Permissions:** Under the "Repository permissions" section, grant the following permissions required for the example workflows: + * **Contents:** `Read & write` + * **Issues:** `Read & write` + * **Pull requests:** `Read & write` + > **Note:** Always adhere to the principle of least privilege. If your custom workflows require fewer permissions, adjust these settings accordingly. +5. Click **Create GitHub App**. + +### Step 2: Generate a Private Key and Get the App ID + +1. After your app is created, you will be returned to its settings page. Click **Generate a private key**. +2. Save the downloaded `.pem` file securely. This file is your app's private key and is highly sensitive. +3. Make a note of the **App ID** listed at the top of the settings page. + +### Step 3: Install the App in Your Repository + +1. From your app's settings page, select **Install App** from the left sidebar. +2. Choose the organization or account where you want to install the app. +3. Select **Only select repositories** and choose the repository (or repositories) where you intend to use the action. +4. Click **Install**. + +### Step 4: Configure Repository Variables and Secrets + +1. Navigate to your repository's **Settings** > **Secrets and variables** > **Actions**. +2. Select the **Variables** tab and click **New repository variable**. + * **Name:** `APP_ID` + * **Value:** Enter the App ID you noted earlier. +3. Select the **Secrets** tab and click **New repository secret**. + * **Name:** `PRIVATE_KEY` + * **Secret:** Paste the entire contents of the `.pem` file you downloaded. + + +## Using the Default `GITHUB_TOKEN` + +For simpler scenarios, the action can authenticate using the default `GITHUB_TOKEN` that GitHub automatically creates for each workflow run. + +If the `APP_ID` and `PRIVATE_KEY` secrets are not configured in your repository, the action will automatically fall back to this method. + +**Limitations:** +* **Limited Permissions:** The `GITHUB_TOKEN` has a restricted set of permissions. You may need to grant additional permissions directly within your workflow file to enable specific functionalities. +* **Job-Scoped:** The token's access is limited to the repository where the workflow is running and expires when the job is complete. + + +## Workflow Configuration Examples + +For complete, working examples of how to configure authentication, please refer to the workflows in the [`/examples`](../examples) directory. + +These examples demonstrate how to set up conditional authentication that works with both a GitHub App and the default `GITHUB_TOKEN`. diff --git a/examples/gemini-issue-automated-triage.yml b/examples/gemini-issue-automated-triage.yml index dae99a6..16cb116 100644 --- a/examples/gemini-issue-automated-triage.yml +++ b/examples/gemini-issue-automated-triage.yml @@ -1,4 +1,4 @@ -name: Gemini Automated Issue Triage +name: 🏷️ Gemini Automated Issue Triage on: issues: @@ -18,20 +18,21 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout repository uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} - name: Run Gemini Issue Triage uses: google-gemini/gemini-cli-action@main env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} ISSUE_TITLE: ${{ github.event.issue.title }} ISSUE_BODY: ${{ github.event.issue.body }} ISSUE_NUMBER: ${{ github.event.issue.number }} @@ -57,13 +58,14 @@ jobs: You are an issue triage assistant. Analyze the current GitHub issue and apply the most appropriate existing labels. Steps: - 1. Run: `gh label list --limit 100` to get all available labels. + 1. Run: `gh label list` to get all available labels. 2. Review the issue title and body provided in the environment variables. - 3. Select the most relevant labels from the existing labels, focusing on kind/*, area/*, and priority/*. + 3. Select the most relevant labels from the existing labels. If available, set labels that follow the `kind/*`, `area/*`, and `priority/*` patterns. 4. Apply the selected labels to this issue using: `gh issue edit ISSUE_NUMBER --add-label "label1,label2"` + 5. If the `status/needs-triage` label is present, remove it using: `gh issue edit ISSUE_NUMBER --remove-label "status/needs-triage"` Guidelines: - Only use labels that already exist in the repository. - Do not add comments or modify the issue content. - Triage only the current issue. - - Assign all applicable kind/*, area/*, and priority/* labels based on the issue content. + - Assign all applicable labels based on the issue content. diff --git a/examples/gemini-issue-scheduled-triage.yml b/examples/gemini-issue-scheduled-triage.yml index 39513b0..497422a 100644 --- a/examples/gemini-issue-scheduled-triage.yml +++ b/examples/gemini-issue-scheduled-triage.yml @@ -1,4 +1,4 @@ -name: Scheduled Issue Triage +name: 📋 Gemini Scheduled Issue Triage on: schedule: @@ -16,40 +16,52 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout repository uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} - name: Find untriaged issues id: find_issues env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} run: | + echo "🔍 Finding issues without labels..." NO_LABEL_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue no:label" --json number,title,body) - NEEDS_TRIAGE_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue label:\"status/needs-triage\"" --json number,title,body) - ISSUES=$(echo "$NO_LABEL_ISSUES" "$NEEDS_TRIAGE_ISSUES" | jq -c -s 'add | unique_by(.number)') + + echo "🏷️ Finding issues that need triage..." + NEED_TRIAGE_ISSUES=$(gh issue list --repo ${{ github.repository }} --search "is:open is:issue label:\"status/needs-triage\"" --json number,title,body) + + echo "🔄 Merging and deduplicating issues..." + ISSUES=$(echo "$NO_LABEL_ISSUES" "$NEED_TRIAGE_ISSUES" | jq -c -s 'add | unique_by(.number)') + + echo "📝 Setting output for GitHub Actions..." echo "issues_to_triage=$ISSUES" >> "$GITHUB_OUTPUT" + echo "✅ Found $(echo "$ISSUES" | jq 'length') issues to triage! 🎯" + - name: Run Gemini Issue Triage if: steps.find_issues.outputs.issues_to_triage != '[]' uses: google-gemini/gemini-cli-action@main env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} ISSUES_TO_TRIAGE: ${{ steps.find_issues.outputs.issues_to_triage }} REPOSITORY: ${{ github.repository }} with: + version: 0.1.8-rc.0 GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} OTLP_GCP_WIF_PROVIDER: ${{ secrets.OTLP_GCP_WIF_PROVIDER }} OTLP_GOOGLE_CLOUD_PROJECT: ${{ secrets.OTLP_GOOGLE_CLOUD_PROJECT }} settings_json: | { "coreTools": [ + "run_shell_command(echo)", "run_shell_command(gh label list)", "run_shell_command(gh issue edit)", "run_shell_command(gh issue list)" @@ -61,26 +73,15 @@ jobs: "sandbox": false } prompt: | - You are an issue triage assistant for GitHub issues. - Your task is to analyze a batch of issues and apply appropriate labels from the repository's list of available labels. - - **IMPORTANT: Your only action should be to apply labels. Do not post any comments or modify any code.** - - **Triage Workflow:** - - 1. **Fetch Available Labels:** - Execute: `gh label list` - - 2. **Get Issues to Triage:** - The issues needing triage are available in the environment variable $ISSUES_TO_TRIAGE (JSON format) - Repository: $REPOSITORY - - 3. **Analyze and Apply Labels:** - For each issue in the list, analyze its title and body, then apply appropriate labels using: - `gh issue edit ISSUE_NUMBER --add-label "label1,label2"` - - **Guidelines:** - - Only use labels that exist in the repository - - Do not add comments to any issue + You are an issue triage assistant. Analyze issues and apply appropriate labels. + + Steps: + 1. Run: `gh label list` + 2. Check environment variable: $ISSUES_TO_TRIAGE (JSON array of issues) + 3. For each issue, apply labels: `gh issue edit ISSUE_NUMBER --add-label "label1,label2"`. If available, set labels that follow the `kind/*`, `area/*`, and `priority/*` patterns. + 4. For each issue, if the `status/needs-triage` label is present, remove it using: `gh issue edit ISSUE_NUMBER --remove-label "status/needs-triage"` + + Guidelines: + - Only use existing repository labels + - Do not add comments - Triage each issue independently - - Common label patterns: kind/bug, kind/enhancement, kind/documentation, area/*, priority/* diff --git a/examples/gemini-pr-review.yml b/examples/gemini-pr-review.yml index 6d03f44..35c4d5f 100644 --- a/examples/gemini-pr-review.yml +++ b/examples/gemini-pr-review.yml @@ -1,4 +1,4 @@ -name: Gemini PR Review +name: 🧐 Gemini Pull Request Review on: issue_comment: @@ -30,22 +30,22 @@ jobs: steps: - name: Generate GitHub App Token id: generate_token + if: ${{ vars.APP_ID }} uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.APP_ID }} + app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.PRIVATE_KEY }} - name: Checkout PR code uses: actions/checkout@v4 with: - token: ${{ steps.generate_token.outputs.token }} - ref: ${{ github.event.pull_request.head.sha }} + token: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} fetch-depth: 0 - name: Get PR details id: get_pr env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then PR_NUMBER=${{ github.event.inputs.pr_number }} @@ -64,7 +64,7 @@ jobs: ADDITIONAL_INSTRUCTIONS=$(echo "$COMMENT_BODY" | sed 's/.*@gemini-cli \/review//' | xargs) fi echo "additional_instructions=$ADDITIONAL_INSTRUCTIONS" >> "$GITHUB_OUTPUT" - + # Get PR details PR_DATA=$(gh pr view $PR_NUMBER --json title,body,additions,deletions,changedFiles,baseRefName,headRefName) echo "pr_data=$PR_DATA" >> "$GITHUB_OUTPUT" @@ -76,9 +76,9 @@ jobs: echo "EOF" >> "$GITHUB_OUTPUT" - name: Run Gemini PR Review - uses: ./ + uses: google-gemini/gemini-cli-action@main env: - GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }} PR_DATA: ${{ steps.get_pr.outputs.pr_data }} CHANGED_FILES: ${{ steps.get_pr.outputs.changed_files }} @@ -128,16 +128,6 @@ jobs: Once you have the information, provide a comprehensive code review by: 1. Writing your review to a file: write_file("review.md", "") 2. Posting the review: gh pr comment $PR_NUMBER --body-file review.md --repo $REPOSITORY - - Review Guidelines: - - Focus on code quality, security, performance, and maintainability - - Check for common issues: potential bugs, security vulnerabilities, performance bottlenecks - - Verify error handling and edge cases - - Look for code style and best practices - - Comment on architecture and design decisions if significant - - Be constructive and specific in feedback - - Highlight both issues and positive aspects - - Suggest improvements with examples when possible Review Areas: - **Security**: Authentication, authorization, input validation, data sanitization @@ -188,6 +178,3 @@ jobs: - Mention specific good practices or implementations - Acknowledge well-written code sections - Note improvements from previous versions - - --- - *Review completed by Gemini CLI*