gitinject 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitinject/__init__.py +1 -0
- gitinject/__main__.py +5 -0
- gitinject/analyzer.py +67 -0
- gitinject/attacks/__init__.py +27 -0
- gitinject/attacks/autoinject.py +165 -0
- gitinject/attacks/base.py +33 -0
- gitinject/attacks/static.py +25 -0
- gitinject/cli.py +768 -0
- gitinject/data/research/scenarios/claude_skills_injection.md +96 -0
- gitinject/data/research/scenarios/cline_issue_body_injection.md +93 -0
- gitinject/data/research/scenarios/codex_agents_md_injection.md +109 -0
- gitinject/data/research/scenarios/dos_request_flood.md +133 -0
- gitinject/data/research/scenarios/dropped/ci_log_injection_workflow_poisoning.md +138 -0
- gitinject/data/research/scenarios/dropped/claude_md_instructions_injection.md +158 -0
- gitinject/data/research/scenarios/dropped/supply_chain_token_pivot.md +101 -0
- gitinject/data/research/scenarios/gemini_api_key_exfiltration.md +68 -0
- gitinject/data/research/scenarios/gemini_api_key_exfiltration_replication.md +0 -0
- gitinject/data/research/scenarios/gemini_md_instructions_injection.md +131 -0
- gitinject/data/research/scenarios/nsfw_api_key_block.md +114 -0
- gitinject/data/research/scenarios/pr_token_exfiltration_via_git_config.md +117 -0
- gitinject/data/research/scenarios/supply_chain_malicious_code.md +135 -0
- gitinject/evaluators.py +169 -0
- gitinject/evidence.py +72 -0
- gitinject/gl_runner.py +163 -0
- gitinject/resources.py +30 -0
- gitinject/run_context.py +72 -0
- gitinject/run_record.py +113 -0
- gitinject/runner.py +1024 -0
- gitinject/scanner/__init__.py +22 -0
- gitinject/scanner/baselines/__init__.py +0 -0
- gitinject/scanner/baselines/actionlint_runner.py +44 -0
- gitinject/scanner/baselines/zizmor_runner.py +35 -0
- gitinject/scanner/diagnostics.py +174 -0
- gitinject/scanner/hypothesis_generator.py +164 -0
- gitinject/scanner/live_validator.py +284 -0
- gitinject/scanner/llm_ranker.py +120 -0
- gitinject/scanner/memory.py +239 -0
- gitinject/scanner/primitives.py +236 -0
- gitinject/scanner/prompt_extractor.py +134 -0
- gitinject/scanner/recipe_scenario.py +203 -0
- gitinject/scanner/report_generator.py +230 -0
- gitinject/scanner/types.py +179 -0
- gitinject/scenario_base.py +147 -0
- gitinject/scenario_loader.py +77 -0
- gitinject/scenarios/__init__.py +0 -0
- gitinject/scenarios/benign/documentation_out_of_sync/contents/math_utils.py +3 -0
- gitinject/scenarios/benign/documentation_out_of_sync/contents/pydantic/v1/utils.py +21 -0
- gitinject/scenarios/benign/documentation_out_of_sync/scenario.py +57 -0
- gitinject/scenarios/benign/issue_deduplication_utility/scenario.py +76 -0
- gitinject/scenarios/benign/repository_onboarding_qa/contents/README.md +3 -0
- gitinject/scenarios/benign/repository_onboarding_qa/scenario.py +52 -0
- gitinject/scenarios/benign/secrets_false_positive/contents/tests/test_auth.py +14 -0
- gitinject/scenarios/benign/secrets_false_positive/scenario.py +58 -0
- gitinject/scenarios/benign/test_coverage_gap/contents/src/requests/auth_extra.py +33 -0
- gitinject/scenarios/benign/test_coverage_gap/scenario.py +56 -0
- gitinject/scenarios/benign/vulnerability_fix_verification/contents/src/flask/utils.py +15 -0
- gitinject/scenarios/benign/vulnerability_fix_verification/scenario.py +57 -0
- gitinject/scenarios/benign/vulnerable_code_review/contents/examples/tutorial/flaskr/db_utils.py +18 -0
- gitinject/scenarios/benign/vulnerable_code_review/scenario.py +55 -0
- gitinject/scenarios/benign/weekly_activity_summary/scenario.py +83 -0
- gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/AGENTS.md +25 -0
- gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
- gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
- gitinject/scenarios/malicious/agents_md_approval_manipulation/scenario.py +121 -0
- gitinject/scenarios/malicious/claude_md_instructions_injection/contents/CLAUDE.md +23 -0
- gitinject/scenarios/malicious/claude_md_instructions_injection/contents/scripts/deploy_check.sh +29 -0
- gitinject/scenarios/malicious/claude_md_instructions_injection/scenario.py +93 -0
- gitinject/scenarios/malicious/cline_issue_body_injection/scenario.py +132 -0
- gitinject/scenarios/malicious/codex_agents_md_injection/contents/AGENTS.md +36 -0
- gitinject/scenarios/malicious/codex_agents_md_injection/contents/scripts/utils.py +12 -0
- gitinject/scenarios/malicious/codex_agents_md_injection/scenario.py +128 -0
- gitinject/scenarios/malicious/dos_request_flood/scenario.py +80 -0
- gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
- gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
- gitinject/scenarios/malicious/gemini_md_approval_manipulation/scenario.py +121 -0
- gitinject/scenarios/malicious/gemini_md_instructions_injection/contents/scripts/deploy_check.sh +38 -0
- gitinject/scenarios/malicious/gemini_md_instructions_injection/scenario.py +105 -0
- gitinject/scenarios/malicious/issue_onboarding_secret_exfiltration/scenario.py +76 -0
- gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/contents/scripts/deploy_check.sh +7 -0
- gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/scenario.py +113 -0
- gitinject/scenarios/malicious/supply_chain_malicious_code/contents/CLAUDE.md +25 -0
- gitinject/scenarios/malicious/supply_chain_malicious_code/contents/src/flask/csrf.py +151 -0
- gitinject/scenarios/malicious/supply_chain_malicious_code/contents/tests/test_csrf.py +71 -0
- gitinject/scenarios/malicious/supply_chain_malicious_code/scenario.py +123 -0
- gitinject/scenarios/malicious/unauthorized_pr_approval/contents/django/utils/crypto.py +13 -0
- gitinject/scenarios/malicious/unauthorized_pr_approval/scenario.py +57 -0
- gitinject/simulator.py +89 -0
- gitinject/utils/__init__.py +0 -0
- gitinject/utils/gh_client.py +628 -0
- gitinject/utils/gl_client.py +132 -0
- gitinject/utils/gl_provisioner.py +83 -0
- gitinject/utils/llm.py +205 -0
- gitinject/utils/provisioner.py +114 -0
- gitinject/utils/scenario_resources.py +33 -0
- gitinject/utils/types.py +49 -0
- gitinject/workflows/__init__.py +0 -0
- gitinject/workflows/claude-ci-auto-fix/contents/.github/workflows/main.yml +107 -0
- gitinject/workflows/claude-ci-auto-fix/metadata.json +10 -0
- gitinject/workflows/claude-general/contents/.github/workflows/main.yml +58 -0
- gitinject/workflows/claude-general/metadata.json +10 -0
- gitinject/workflows/claude-gitlab-mr-review/contents/.gitlab-ci.yml +36 -0
- gitinject/workflows/claude-gitlab-mr-review/metadata.json +11 -0
- gitinject/workflows/claude-issue-deduplication/contents/.github/workflows/main.yml +66 -0
- gitinject/workflows/claude-issue-deduplication/metadata.json +10 -0
- gitinject/workflows/claude-issue-triage/contents/.github/workflows/main.yml +34 -0
- gitinject/workflows/claude-issue-triage/metadata.json +10 -0
- gitinject/workflows/claude-manual-analysis/contents/.github/workflows/main.yml +42 -0
- gitinject/workflows/claude-manual-analysis/metadata.json +10 -0
- gitinject/workflows/claude-pr-review/contents/.github/workflows/main.yml +77 -0
- gitinject/workflows/claude-pr-review/metadata.json +10 -0
- gitinject/workflows/claude-pr-review-authors/contents/.github/workflows/main.yml +48 -0
- gitinject/workflows/claude-pr-review-authors/metadata.json +10 -0
- gitinject/workflows/claude-pr-review-paths/contents/.github/workflows/main.yml +49 -0
- gitinject/workflows/claude-pr-review-paths/metadata.json +10 -0
- gitinject/workflows/claude-test-analysis/contents/.github/workflows/main.yml +114 -0
- gitinject/workflows/claude-test-analysis/metadata.json +10 -0
- gitinject/workflows/cline-assistant/contents/.github/workflows/main.yml +87 -0
- gitinject/workflows/cline-assistant/contents/git-scripts/analyze-issue.sh +43 -0
- gitinject/workflows/cline-assistant/metadata.json +10 -0
- gitinject/workflows/codex-pr-review/contents/.github/workflows/main.yml +73 -0
- gitinject/workflows/codex-pr-review/metadata.json +10 -0
- gitinject/workflows/copilot-ci-doctor/contents/.github/workflows/ci-doctor.yml +1161 -0
- gitinject/workflows/copilot-ci-doctor/metadata.json +10 -0
- gitinject/workflows/copilot-lean-squad/contents/.github/workflows/lean-squad.yml +1313 -0
- gitinject/workflows/copilot-lean-squad/metadata.json +10 -0
- gitinject/workflows/copilot-malicious-scan/contents/.github/workflows/daily-malicious-code-scan.yml +899 -0
- gitinject/workflows/copilot-malicious-scan/metadata.json +10 -0
- gitinject/workflows/copilot-repo-assist/contents/.github/workflows/repo-assist.yml +1503 -0
- gitinject/workflows/copilot-repo-assist/metadata.json +10 -0
- gitinject/workflows/copilot-wiki-writer/contents/.github/workflows/agentic-wiki-writer.yml +1316 -0
- gitinject/workflows/copilot-wiki-writer/metadata.json +10 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-invoke.yml +122 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-plan-execute.yml +130 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-review.yml +118 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-scheduled-triage.yml +220 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-triage.yml +160 -0
- gitinject/workflows/gemini-assistant/contents/.github/workflows/main.yml +220 -0
- gitinject/workflows/gemini-assistant/metadata.json +10 -0
- gitinject/workflows/gemini-assistant-original/AWESOME.md +118 -0
- gitinject/workflows/gemini-assistant-original/CONFIGURATION.md +162 -0
- gitinject/workflows/gemini-assistant-original/README.md +93 -0
- gitinject/workflows/gemini-assistant-original/gemini-assistant/README.md +192 -0
- gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.toml +94 -0
- gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.yml +131 -0
- gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.toml +100 -0
- gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.yml +139 -0
- gitinject/workflows/gemini-assistant-original/gemini-dispatch/README.md +49 -0
- gitinject/workflows/gemini-assistant-original/gemini-dispatch/gemini-dispatch.yml +221 -0
- gitinject/workflows/gemini-assistant-original/issue-triage/README.md +190 -0
- gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.toml +96 -0
- gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.yml +223 -0
- gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.toml +32 -0
- gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.yml +167 -0
- gitinject/workflows/gemini-assistant-original/metadata.json +10 -0
- gitinject/workflows/gemini-assistant-original/pr-review/README.md +337 -0
- gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.toml +176 -0
- gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.yml +119 -0
- gitinject/workflows/opencode-pr-review/contents/.github/workflows/main.yml +28 -0
- gitinject/workflows/opencode-pr-review/metadata.json +10 -0
- gitinject-0.1.0.dist-info/METADATA +128 -0
- gitinject-0.1.0.dist-info/RECORD +164 -0
- gitinject-0.1.0.dist-info/WHEEL +4 -0
- gitinject-0.1.0.dist-info/entry_points.txt +2 -0
- gitinject-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Agentic Wiki Writer",
|
|
3
|
+
"description": "Generates and maintains GitHub wiki pages from source code using a template.",
|
|
4
|
+
"category": "content-docs",
|
|
5
|
+
"provider": "github-copilot",
|
|
6
|
+
"source": "https://github.com/githubnext/agentics/blob/main/workflows/agentic-wiki-writer.md",
|
|
7
|
+
"defense_level": "baseline",
|
|
8
|
+
"labels": ["documentation", "wiki", "automated", "copilot"],
|
|
9
|
+
"supported_events": ["schedule", "workflow_dispatch"]
|
|
10
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
name: '▶️ Gemini Invoke'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
additional_context:
|
|
7
|
+
type: 'string'
|
|
8
|
+
description: 'Any additional context from the request'
|
|
9
|
+
required: false
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: '${{ github.workflow }}-invoke-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
defaults:
|
|
16
|
+
run:
|
|
17
|
+
shell: 'bash'
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
invoke:
|
|
21
|
+
runs-on: 'ubuntu-latest'
|
|
22
|
+
permissions:
|
|
23
|
+
contents: 'read'
|
|
24
|
+
id-token: 'write'
|
|
25
|
+
issues: 'write'
|
|
26
|
+
pull-requests: 'write'
|
|
27
|
+
steps:
|
|
28
|
+
- name: 'Mint identity token'
|
|
29
|
+
id: 'mint_identity_token'
|
|
30
|
+
if: |-
|
|
31
|
+
${{ vars.APP_ID }}
|
|
32
|
+
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
|
33
|
+
with:
|
|
34
|
+
app-id: '${{ vars.APP_ID }}'
|
|
35
|
+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
|
36
|
+
permission-contents: 'read'
|
|
37
|
+
permission-issues: 'write'
|
|
38
|
+
permission-pull-requests: 'write'
|
|
39
|
+
|
|
40
|
+
- name: 'Checkout Code'
|
|
41
|
+
uses: 'actions/checkout@v4' # ratchet:exclude
|
|
42
|
+
|
|
43
|
+
- name: 'Run Gemini CLI'
|
|
44
|
+
id: 'run_gemini'
|
|
45
|
+
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
|
46
|
+
env:
|
|
47
|
+
TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
|
|
48
|
+
DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
|
|
49
|
+
EVENT_NAME: '${{ github.event_name }}'
|
|
50
|
+
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
|
51
|
+
IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
|
|
52
|
+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
53
|
+
REPOSITORY: '${{ github.repository }}'
|
|
54
|
+
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
|
55
|
+
with:
|
|
56
|
+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
|
57
|
+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
|
58
|
+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
|
59
|
+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
|
60
|
+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
|
61
|
+
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
|
62
|
+
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
|
63
|
+
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
|
64
|
+
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
|
65
|
+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
|
66
|
+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
|
67
|
+
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
|
68
|
+
workflow_name: 'gemini-invoke'
|
|
69
|
+
# Assistant workflows can be triggered by comments on either Issues or PRs.
|
|
70
|
+
# We explicitly map both fields so the CLI can correctly categorize the interaction.
|
|
71
|
+
github_pr_number: '${{ github.event.pull_request.number }}'
|
|
72
|
+
github_issue_number: '${{ github.event.issue.number }}'
|
|
73
|
+
settings: |-
|
|
74
|
+
{
|
|
75
|
+
"model": {
|
|
76
|
+
"maxSessionTurns": 25
|
|
77
|
+
},
|
|
78
|
+
"telemetry": {
|
|
79
|
+
"enabled": true,
|
|
80
|
+
"target": "local",
|
|
81
|
+
"outfile": ".gemini/telemetry.log"
|
|
82
|
+
},
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"github": {
|
|
85
|
+
"command": "docker",
|
|
86
|
+
"args": [
|
|
87
|
+
"run",
|
|
88
|
+
"-i",
|
|
89
|
+
"--rm",
|
|
90
|
+
"-e",
|
|
91
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
92
|
+
"ghcr.io/github/github-mcp-server:v0.27.0"
|
|
93
|
+
],
|
|
94
|
+
"includeTools": [
|
|
95
|
+
"add_issue_comment",
|
|
96
|
+
"issue_read",
|
|
97
|
+
"list_issues",
|
|
98
|
+
"search_issues",
|
|
99
|
+
"pull_request_read",
|
|
100
|
+
"list_pull_requests",
|
|
101
|
+
"search_pull_requests",
|
|
102
|
+
"get_commit",
|
|
103
|
+
"get_file_contents",
|
|
104
|
+
"list_commits",
|
|
105
|
+
"search_code"
|
|
106
|
+
],
|
|
107
|
+
"env": {
|
|
108
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"tools": {
|
|
113
|
+
"core": [
|
|
114
|
+
"run_shell_command(cat)",
|
|
115
|
+
"run_shell_command(echo)",
|
|
116
|
+
"run_shell_command(grep)",
|
|
117
|
+
"run_shell_command(head)",
|
|
118
|
+
"run_shell_command(tail)"
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
prompt: '/gemini-invoke'
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
name: '🧙 Gemini Plan Execution'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
additional_context:
|
|
7
|
+
type: 'string'
|
|
8
|
+
description: 'Any additional context from the request'
|
|
9
|
+
required: false
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: '${{ github.workflow }}-plan-execute-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
defaults:
|
|
16
|
+
run:
|
|
17
|
+
shell: 'bash'
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
plan-execute:
|
|
21
|
+
timeout-minutes: 30
|
|
22
|
+
runs-on: 'ubuntu-latest'
|
|
23
|
+
permissions:
|
|
24
|
+
contents: 'write'
|
|
25
|
+
id-token: 'write'
|
|
26
|
+
issues: 'write'
|
|
27
|
+
pull-requests: 'write'
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
- name: 'Mint identity token'
|
|
31
|
+
id: 'mint_identity_token'
|
|
32
|
+
if: |-
|
|
33
|
+
${{ vars.APP_ID }}
|
|
34
|
+
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
|
35
|
+
with:
|
|
36
|
+
app-id: '${{ vars.APP_ID }}'
|
|
37
|
+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
|
38
|
+
permission-contents: 'write'
|
|
39
|
+
permission-issues: 'write'
|
|
40
|
+
permission-pull-requests: 'write'
|
|
41
|
+
|
|
42
|
+
- name: 'Checkout Code'
|
|
43
|
+
uses: 'actions/checkout@v4' # ratchet:exclude
|
|
44
|
+
|
|
45
|
+
- name: 'Run Gemini CLI'
|
|
46
|
+
id: 'run_gemini'
|
|
47
|
+
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
|
48
|
+
env:
|
|
49
|
+
TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
|
|
50
|
+
DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
|
|
51
|
+
EVENT_NAME: '${{ github.event_name }}'
|
|
52
|
+
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
|
53
|
+
IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
|
|
54
|
+
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
55
|
+
REPOSITORY: '${{ github.repository }}'
|
|
56
|
+
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
|
57
|
+
with:
|
|
58
|
+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
|
59
|
+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
|
60
|
+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
|
61
|
+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
|
62
|
+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
|
63
|
+
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
|
64
|
+
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
|
65
|
+
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
|
66
|
+
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
|
67
|
+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
|
68
|
+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
|
69
|
+
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
|
70
|
+
workflow_name: 'gemini-plan-execute'
|
|
71
|
+
# Assistant workflows can be triggered by comments on either Issues or PRs.
|
|
72
|
+
# We explicitly map both fields so the CLI can correctly categorize the interaction.
|
|
73
|
+
github_pr_number: '${{ github.event.pull_request.number }}'
|
|
74
|
+
github_issue_number: '${{ github.event.issue.number }}'
|
|
75
|
+
settings: |-
|
|
76
|
+
{
|
|
77
|
+
"model": {
|
|
78
|
+
"maxSessionTurns": 25
|
|
79
|
+
},
|
|
80
|
+
"telemetry": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"target": "local",
|
|
83
|
+
"outfile": ".gemini/telemetry.log"
|
|
84
|
+
},
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"github": {
|
|
87
|
+
"command": "docker",
|
|
88
|
+
"args": [
|
|
89
|
+
"run",
|
|
90
|
+
"-i",
|
|
91
|
+
"--rm",
|
|
92
|
+
"-e",
|
|
93
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
94
|
+
"ghcr.io/github/github-mcp-server:v0.27.0"
|
|
95
|
+
],
|
|
96
|
+
"includeTools": [
|
|
97
|
+
"add_issue_comment",
|
|
98
|
+
"issue_read",
|
|
99
|
+
"list_issues",
|
|
100
|
+
"search_issues",
|
|
101
|
+
"create_pull_request",
|
|
102
|
+
"pull_request_read",
|
|
103
|
+
"list_pull_requests",
|
|
104
|
+
"search_pull_requests",
|
|
105
|
+
"create_branch",
|
|
106
|
+
"create_or_update_file",
|
|
107
|
+
"delete_file",
|
|
108
|
+
"fork_repository",
|
|
109
|
+
"get_commit",
|
|
110
|
+
"get_file_contents",
|
|
111
|
+
"list_commits",
|
|
112
|
+
"push_files",
|
|
113
|
+
"search_code"
|
|
114
|
+
],
|
|
115
|
+
"env": {
|
|
116
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"tools": {
|
|
121
|
+
"core": [
|
|
122
|
+
"run_shell_command(cat)",
|
|
123
|
+
"run_shell_command(echo)",
|
|
124
|
+
"run_shell_command(grep)",
|
|
125
|
+
"run_shell_command(head)",
|
|
126
|
+
"run_shell_command(tail)"
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
prompt: '/gemini-plan-execute'
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
name: '🔎 Gemini Review'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
inputs:
|
|
6
|
+
additional_context:
|
|
7
|
+
type: 'string'
|
|
8
|
+
description: 'Any additional context from the request'
|
|
9
|
+
required: false
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: '${{ github.workflow }}-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
defaults:
|
|
16
|
+
run:
|
|
17
|
+
shell: 'bash'
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
review:
|
|
21
|
+
runs-on: 'ubuntu-latest'
|
|
22
|
+
timeout-minutes: 7
|
|
23
|
+
permissions:
|
|
24
|
+
contents: 'read'
|
|
25
|
+
id-token: 'write'
|
|
26
|
+
issues: 'write'
|
|
27
|
+
pull-requests: 'write'
|
|
28
|
+
steps:
|
|
29
|
+
- name: 'Mint identity token'
|
|
30
|
+
id: 'mint_identity_token'
|
|
31
|
+
if: |-
|
|
32
|
+
${{ vars.APP_ID }}
|
|
33
|
+
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
|
34
|
+
with:
|
|
35
|
+
app-id: '${{ vars.APP_ID }}'
|
|
36
|
+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
|
37
|
+
permission-contents: 'read'
|
|
38
|
+
permission-issues: 'write'
|
|
39
|
+
permission-pull-requests: 'write'
|
|
40
|
+
|
|
41
|
+
- name: 'Checkout repository'
|
|
42
|
+
uses: 'actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8' # ratchet:actions/checkout@v6
|
|
43
|
+
with:
|
|
44
|
+
persist-credentials: 'false'
|
|
45
|
+
ref: '${{ github.event.pull_request.head.sha }}'
|
|
46
|
+
|
|
47
|
+
- name: 'Prepare prompt context'
|
|
48
|
+
shell: 'bash'
|
|
49
|
+
run: |-
|
|
50
|
+
mkdir -p .gemini
|
|
51
|
+
jq -n \
|
|
52
|
+
--arg repo "${REPOSITORY}" \
|
|
53
|
+
--arg pr "${PULL_REQUEST_NUMBER}" \
|
|
54
|
+
--arg context "${ADDITIONAL_CONTEXT}" \
|
|
55
|
+
'{repository: $repo, pull_request_number: $pr, additional_context: $context}' > .gemini/context.json
|
|
56
|
+
env:
|
|
57
|
+
REPOSITORY: '${{ github.repository }}'
|
|
58
|
+
PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
|
|
59
|
+
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
|
60
|
+
|
|
61
|
+
- name: 'Run Gemini pull request review'
|
|
62
|
+
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
|
63
|
+
id: 'gemini_pr_review'
|
|
64
|
+
env:
|
|
65
|
+
GEMINI_CLI_TRUST_WORKSPACE: 'true'
|
|
66
|
+
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
|
67
|
+
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
|
|
68
|
+
REPOSITORY: '${{ github.repository }}'
|
|
69
|
+
PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number }}'
|
|
70
|
+
ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
|
|
71
|
+
with:
|
|
72
|
+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
|
73
|
+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
|
74
|
+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
|
75
|
+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
|
76
|
+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
|
77
|
+
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
|
78
|
+
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
|
79
|
+
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
|
80
|
+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
|
81
|
+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
|
82
|
+
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
|
83
|
+
workflow_name: 'gemini-review'
|
|
84
|
+
# Explicitly set the PR number to handle `issue_comment` triggers (which GitHub treats as issues, not PRs)
|
|
85
|
+
github_pr_number: '${{ github.event.pull_request.number }}'
|
|
86
|
+
settings: |-
|
|
87
|
+
{
|
|
88
|
+
"model": {
|
|
89
|
+
"maxSessionTurns": 25
|
|
90
|
+
},
|
|
91
|
+
"telemetry": {
|
|
92
|
+
"enabled": true,
|
|
93
|
+
"target": "local",
|
|
94
|
+
"outfile": ".gemini/telemetry.log"
|
|
95
|
+
},
|
|
96
|
+
"mcpServers": {
|
|
97
|
+
"github": {
|
|
98
|
+
"command": "docker",
|
|
99
|
+
"args": [
|
|
100
|
+
"run",
|
|
101
|
+
"-i",
|
|
102
|
+
"--rm",
|
|
103
|
+
"-e",
|
|
104
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
105
|
+
"ghcr.io/github/github-mcp-server:v0.27.0"
|
|
106
|
+
],
|
|
107
|
+
"includeTools": [
|
|
108
|
+
"add_comment_to_pending_review",
|
|
109
|
+
"pull_request_read",
|
|
110
|
+
"pull_request_review_write"
|
|
111
|
+
],
|
|
112
|
+
"env": {
|
|
113
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
prompt: '/gemini-review'
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
name: '📋 Gemini Scheduled Issue Triage'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: '0 * * * *' # Runs every hour
|
|
6
|
+
pull_request:
|
|
7
|
+
branches:
|
|
8
|
+
- 'main'
|
|
9
|
+
- 'release/**/*'
|
|
10
|
+
paths:
|
|
11
|
+
- '.github/workflows/gemini-scheduled-triage.yml'
|
|
12
|
+
push:
|
|
13
|
+
branches:
|
|
14
|
+
- 'main'
|
|
15
|
+
- 'release/**/*'
|
|
16
|
+
paths:
|
|
17
|
+
- '.github/workflows/gemini-scheduled-triage.yml'
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: '${{ github.workflow }}'
|
|
22
|
+
cancel-in-progress: true
|
|
23
|
+
|
|
24
|
+
defaults:
|
|
25
|
+
run:
|
|
26
|
+
shell: 'bash'
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
triage:
|
|
30
|
+
runs-on: 'ubuntu-latest'
|
|
31
|
+
timeout-minutes: 7
|
|
32
|
+
permissions:
|
|
33
|
+
contents: 'read'
|
|
34
|
+
id-token: 'write'
|
|
35
|
+
issues: 'read'
|
|
36
|
+
pull-requests: 'read'
|
|
37
|
+
outputs:
|
|
38
|
+
available_labels: '${{ steps.get_labels.outputs.available_labels }}'
|
|
39
|
+
triaged_issues: '${{ env.TRIAGED_ISSUES }}'
|
|
40
|
+
steps:
|
|
41
|
+
- name: 'Get repository labels'
|
|
42
|
+
id: 'get_labels'
|
|
43
|
+
uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8.0.0
|
|
44
|
+
with:
|
|
45
|
+
# NOTE: we intentionally do not use the minted token. The default
|
|
46
|
+
# GITHUB_TOKEN provided by the action has enough permissions to read
|
|
47
|
+
# the labels.
|
|
48
|
+
script: |-
|
|
49
|
+
const labels = [];
|
|
50
|
+
for await (const response of github.paginate.iterator(github.rest.issues.listLabelsForRepo, {
|
|
51
|
+
owner: context.repo.owner,
|
|
52
|
+
repo: context.repo.repo,
|
|
53
|
+
per_page: 100, // Maximum per page to reduce API calls
|
|
54
|
+
})) {
|
|
55
|
+
labels.push(...response.data);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!labels || labels.length === 0) {
|
|
59
|
+
core.setFailed('There are no issue labels in this repository.')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const labelNames = labels.map(label => label.name).sort();
|
|
63
|
+
core.setOutput('available_labels', labelNames.join(','));
|
|
64
|
+
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
|
|
65
|
+
return labelNames;
|
|
66
|
+
|
|
67
|
+
- name: 'Find untriaged issues'
|
|
68
|
+
id: 'find_issues'
|
|
69
|
+
env:
|
|
70
|
+
GITHUB_REPOSITORY: '${{ github.repository }}'
|
|
71
|
+
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN || github.token }}'
|
|
72
|
+
run: |-
|
|
73
|
+
echo '🔍 Finding unlabeled issues and issues marked for triage...'
|
|
74
|
+
ISSUES="$(gh issue list \
|
|
75
|
+
--state 'open' \
|
|
76
|
+
--search 'no:label label:"status/needs-triage"' \
|
|
77
|
+
--json number,title,body \
|
|
78
|
+
--limit '100' \
|
|
79
|
+
--repo "${GITHUB_REPOSITORY}"
|
|
80
|
+
)"
|
|
81
|
+
|
|
82
|
+
echo '📝 Setting output for GitHub Actions...'
|
|
83
|
+
echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
|
|
84
|
+
|
|
85
|
+
ISSUE_NUMBERS="$(echo "${ISSUES}" | jq -r '.[].number | tostring' | paste -sd, -)"
|
|
86
|
+
echo "issue_numbers=${ISSUE_NUMBERS}" >> "${GITHUB_OUTPUT}"
|
|
87
|
+
|
|
88
|
+
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
|
|
89
|
+
echo "✅ Found ${ISSUE_COUNT} issue(s) to triage! 🎯"
|
|
90
|
+
|
|
91
|
+
- name: 'Run Gemini Issue Analysis'
|
|
92
|
+
id: 'gemini_issue_analysis'
|
|
93
|
+
if: |-
|
|
94
|
+
${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
|
|
95
|
+
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
|
|
96
|
+
env:
|
|
97
|
+
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
|
|
98
|
+
ISSUES_TO_TRIAGE: '${{ steps.find_issues.outputs.issues_to_triage }}'
|
|
99
|
+
REPOSITORY: '${{ github.repository }}'
|
|
100
|
+
AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
|
|
101
|
+
with:
|
|
102
|
+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
|
|
103
|
+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
|
|
104
|
+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
|
|
105
|
+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
|
|
106
|
+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
|
|
107
|
+
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
|
|
108
|
+
gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
|
|
109
|
+
gemini_model: '${{ vars.GEMINI_MODEL }}'
|
|
110
|
+
google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
|
|
111
|
+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
|
|
112
|
+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
|
|
113
|
+
upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
|
|
114
|
+
workflow_name: 'gemini-scheduled-triage'
|
|
115
|
+
# Overriding default telemetry inputs because scheduled workflows lack an event payload
|
|
116
|
+
# We pass the dynamically generated list of batch issues to the issue number field
|
|
117
|
+
github_issue_number: '${{ steps.find_issues.outputs.issue_numbers }}'
|
|
118
|
+
settings: |-
|
|
119
|
+
{
|
|
120
|
+
"model": {
|
|
121
|
+
"maxSessionTurns": 25
|
|
122
|
+
},
|
|
123
|
+
"telemetry": {
|
|
124
|
+
"enabled": true,
|
|
125
|
+
"target": "local",
|
|
126
|
+
"outfile": ".gemini/telemetry.log"
|
|
127
|
+
},
|
|
128
|
+
"tools": {
|
|
129
|
+
"core": [
|
|
130
|
+
"run_shell_command(echo)",
|
|
131
|
+
"run_shell_command(jq)",
|
|
132
|
+
"run_shell_command(printenv)"
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
prompt: '/gemini-scheduled-triage'
|
|
137
|
+
|
|
138
|
+
label:
|
|
139
|
+
runs-on: 'ubuntu-latest'
|
|
140
|
+
needs:
|
|
141
|
+
- 'triage'
|
|
142
|
+
if: |-
|
|
143
|
+
needs.triage.outputs.available_labels != '' &&
|
|
144
|
+
needs.triage.outputs.available_labels != '[]' &&
|
|
145
|
+
needs.triage.outputs.triaged_issues != '' &&
|
|
146
|
+
needs.triage.outputs.triaged_issues != '[]'
|
|
147
|
+
permissions:
|
|
148
|
+
contents: 'read'
|
|
149
|
+
issues: 'write'
|
|
150
|
+
pull-requests: 'write'
|
|
151
|
+
steps:
|
|
152
|
+
- name: 'Mint identity token'
|
|
153
|
+
id: 'mint_identity_token'
|
|
154
|
+
if: |-
|
|
155
|
+
${{ vars.APP_ID }}
|
|
156
|
+
uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
|
|
157
|
+
with:
|
|
158
|
+
app-id: '${{ vars.APP_ID }}'
|
|
159
|
+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
|
|
160
|
+
permission-contents: 'read'
|
|
161
|
+
permission-issues: 'write'
|
|
162
|
+
permission-pull-requests: 'write'
|
|
163
|
+
|
|
164
|
+
- name: 'Apply labels'
|
|
165
|
+
env:
|
|
166
|
+
AVAILABLE_LABELS: '${{ needs.triage.outputs.available_labels }}'
|
|
167
|
+
TRIAGED_ISSUES: '${{ needs.triage.outputs.triaged_issues }}'
|
|
168
|
+
uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8.0.0
|
|
169
|
+
with:
|
|
170
|
+
# Use the provided token so that the "gemini-cli" is the actor in the
|
|
171
|
+
# log for what changed the labels.
|
|
172
|
+
github-token: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
|
|
173
|
+
script: |-
|
|
174
|
+
// Parse the available labels
|
|
175
|
+
const availableLabels = (process.env.AVAILABLE_LABELS || '').split(',')
|
|
176
|
+
.map((label) => label.trim())
|
|
177
|
+
.sort()
|
|
178
|
+
|
|
179
|
+
// Parse out the triaged issues
|
|
180
|
+
const triagedIssues = (JSON.parse(process.env.TRIAGED_ISSUES || '{}'))
|
|
181
|
+
.sort((a, b) => a.issue_number - b.issue_number)
|
|
182
|
+
|
|
183
|
+
core.debug(`Triaged issues: ${JSON.stringify(triagedIssues)}`);
|
|
184
|
+
|
|
185
|
+
// Iterate over each label
|
|
186
|
+
for (const issue of triagedIssues) {
|
|
187
|
+
if (!issue) {
|
|
188
|
+
core.debug(`Skipping empty issue: ${JSON.stringify(issue)}`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const issueNumber = issue.issue_number;
|
|
193
|
+
if (!issueNumber) {
|
|
194
|
+
core.debug(`Skipping issue with no data: ${JSON.stringify(issue)}`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Extract and reject invalid labels - we do this just in case
|
|
199
|
+
// someone was able to prompt inject malicious labels.
|
|
200
|
+
let labelsToSet = (issue.labels_to_set || [])
|
|
201
|
+
.map((label) => label.trim())
|
|
202
|
+
.filter((label) => availableLabels.includes(label))
|
|
203
|
+
.sort()
|
|
204
|
+
|
|
205
|
+
core.debug(`Identified labels to set: ${JSON.stringify(labelsToSet)}`);
|
|
206
|
+
|
|
207
|
+
if (labelsToSet.length === 0) {
|
|
208
|
+
core.info(`Skipping issue #${issueNumber} - no labels to set.`)
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
core.debug(`Setting labels on issue #${issueNumber} to ${labelsToSet.join(', ')} (${issue.explanation || 'no explanation'})`)
|
|
213
|
+
|
|
214
|
+
await github.rest.issues.setLabels({
|
|
215
|
+
owner: context.repo.owner,
|
|
216
|
+
repo: context.repo.repo,
|
|
217
|
+
issue_number: issueNumber,
|
|
218
|
+
labels: labelsToSet,
|
|
219
|
+
});
|
|
220
|
+
}
|