feat(pr-generator-infra): configure Cloud Run job, Workflows definition, and Dockerfile (#28431)

This commit is contained in:
joneba-google
2026-08-05 16:04:44 +00:00
committed by GitHub
parent b6b41f79eb
commit bde504f250
4 changed files with 187 additions and 0 deletions
@@ -0,0 +1,38 @@
# Dockerfile for Jetski/Antigravity Worker Job using the Python SDK
# This container runs the manager script (workflow/worker.py) which orchestrates
# the code generation and evaluation in-process using google-antigravity and Firestore synchronization.
FROM python:3.11-slim
# 1. Install system utilities (git is required for repository operations)
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Copy Node.js 20 and npm directly from the official node:20-slim image
COPY --from=node:20-slim /usr/local/bin/node /usr/local/bin/node
COPY --from=node:20-slim /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
# 2. Create non-root system user and establish working directory
RUN useradd -m -u 1000 appuser
WORKDIR /app
# 3. Install Python dependencies using requirements.txt for optimized build layer caching
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# 4. Copy the pipeline orchestration script and prompts with non-root ownership
COPY --chown=appuser:appuser workflow/ /app/workflow/
COPY --chown=appuser:appuser agent_prompts/ /app/agent_prompts/
# 5. Switch to unprivileged user
USER appuser
# 6. Execute script directly
ENTRYPOINT ["python", "/app/workflow/worker.py"]
@@ -0,0 +1,40 @@
apiVersion: 'run.googleapis.com/v1'
kind: 'Job'
metadata:
labels:
cloud.googleapis.com/location: 'us-central1'
name: 'pr-gen-job'
spec:
template:
metadata:
annotations:
run.googleapis.com/client-name: 'gcloud'
run.googleapis.com/client-version: '575.0.1'
run.googleapis.com/execution-environment: 'gen2'
spec:
taskCount: 1
template:
spec:
containers:
- env:
- name: 'GOOGLE_CLOUD_LOCATION'
value: 'global'
- name: 'MODEL_NAME'
value: 'gemini-3.5-flash'
- name: 'FIRESTORE_DATABASE'
value: 'gcli-db'
- name: 'FIRESTORE_COLLECTION'
value: 'issues'
- name: 'GIT_TOKEN'
valueFrom:
secretKeyRef:
key: 'latest'
name: 'PR_GEN_GITHUB_PUSH_KEY'
image: 'us-central1-docker.pkg.dev/gcli-intern-project-2026/pr-gen-repo/jetski-worker:latest'
resources:
limits:
cpu: '2'
memory: '8Gi'
maxRetries: 2
serviceAccountName: 'code-gen-job-execution-sa@gcli-intern-project-2026.iam.gserviceaccount.com'
timeoutSeconds: '3600'
@@ -0,0 +1,6 @@
google-antigravity>=0.1.0
protobuf>=7.35.0
pydantic
google-cloud-firestore>=2.15.0, <3.0.0
google-cloud-storage>=2.14.0
google-genai>=2.0.0
@@ -0,0 +1,103 @@
# Google Cloud Workflow that triggers Cloud Run Job and updates Firestore on failure.
main:
params: ['event']
steps:
- init:
assign:
- project_id: '${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}'
- database_id: '${default(sys.get_env("FIRESTORE_DATABASE"), "gcli-db")}'
- collection_name: '${default(sys.get_env("FIRESTORE_COLLECTION"), "issues")}'
- job_name: 'pr-gen-job' # The Cloud Run Job name
- job_location: 'us-central1'
- workflow_execution_id: '${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}'
# Decode Pub/Sub message
- pubsub_message_bytes: '${base64.decode(event.data.message.data)}'
- firestore_doc_str: '${text.decode(pubsub_message_bytes)}'
- firestore_doc: '${json.decode(firestore_doc_str)}'
- doc_id: '${"github_" + firestore_doc.github_metadata.owner + "_" + firestore_doc.github_metadata.repo + "_" + string(firestore_doc.github_metadata.issue_number)}'
- repo_url: '${"https://github.com/" + firestore_doc.github_metadata.owner + "/" + firestore_doc.github_metadata.repo}'
- status: 'STARTED'
- error_details: null
- validate_doc_id:
switch:
- condition: '${not text.match_regex(doc_id, "^[a-zA-Z0-9_.-]+$")}'
raise: '${"Security Exception: Invalid or unsafe firestore_id format: " + string(doc_id)}'
- run_job:
try:
call: 'googleapis.run.v1.namespaces.jobs.run'
args:
name: '${"namespaces/" + project_id + "/jobs/" + job_name}'
location: '${job_location}'
body:
overrides:
containerOverrides:
- env:
- name: 'FIRESTORE_DOC'
value: '${firestore_doc_str}'
- name: 'REPO_URL'
value: '${repo_url}'
- name: 'USE_ADC'
value: 'true'
- name: 'EXECUTION_ID'
value: '${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}'
- name: 'GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID'
value: '${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}'
- name: 'FIRESTORE_ID'
value: '${doc_id}'
connector_params:
timeout: 7200
result: 'job_result'
except:
as: 'e'
steps:
- handle_job_error:
assign:
- status: 'NEEDS_HUMAN'
- error_details: '${e}'
- update_firestore_on_failure:
try:
call: 'googleapis.firestore.v1.projects.databases.documents.patch'
args:
name: '${"projects/" + project_id + "/databases/" + database_id + "/documents/" + collection_name + "/" + doc_id}'
updateMask:
fieldPaths:
- 'status'
- 'error'
- 'lock.holder'
- 'lock.expires_at'
body:
fields:
status:
stringValue: 'NEEDS_HUMAN'
error:
stringValue: '${"Workflow Execution " + sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID") + " failed: " + json.encode_to_string(error_details)}'
lock:
mapValue:
fields:
holder:
nullValue: 'NULL_VALUE'
expires_at:
nullValue: 'NULL_VALUE'
except:
as: 'fs_err'
steps:
- log_firestore_error:
assign:
- firestore_error: '${fs_err}'
next: 'handle_failure'
next: 'mark_completed'
- handle_failure:
return: '${"Failed: " + json.encode_to_string(error_details)}'
- mark_completed:
assign:
- status: 'COMPLETED'
next: 'finish'
- finish:
return: '${status}'