Skip to content

Commit a40ef14

Browse files
authored
Merge branch 'master' into codex/linear-mention-rob-115-check-if-there-is-any-reference-to
2 parents 7d00d4b + 4f7b821 commit a40ef14

File tree

24 files changed

+658
-22
lines changed

24 files changed

+658
-22
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
name: Docker Build on PR
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
# Cancel in-progress runs for the same PR
8+
concurrency:
9+
group: docker-build-${{ github.head_ref }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
permissions:
17+
contents: 'read'
18+
id-token: 'write'
19+
pull-requests: 'write'
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Check if PR is from fork
25+
id: fork_check
26+
run: |
27+
HEAD_REPO="${{ github.event.pull_request.head.repo.full_name }}"
28+
BASE_REPO="${{ github.repository }}"
29+
30+
if [ -z "$HEAD_REPO" ]; then
31+
# Head repo data is unavailable (repo may have been deleted)
32+
# Treat as fork to avoid attempting authenticated pushes
33+
echo "⚠️ Head repo data is unavailable - skipping authenticated push"
34+
echo "is_fork=true" >> $GITHUB_OUTPUT
35+
elif [ "$HEAD_REPO" != "$BASE_REPO" ]; then
36+
echo "📌 PR is from a fork ($HEAD_REPO != $BASE_REPO) - will build but not push"
37+
echo "is_fork=true" >> $GITHUB_OUTPUT
38+
else
39+
echo "✅ PR is from the same repo ($HEAD_REPO)"
40+
echo "is_fork=false" >> $GITHUB_OUTPUT
41+
fi
42+
43+
- name: Get short SHA
44+
id: short_sha
45+
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
46+
47+
- name: Record start time
48+
id: start_time
49+
run: echo "start=$(date +%s)" >> $GITHUB_OUTPUT
50+
51+
- name: Comment build started
52+
if: steps.fork_check.outputs.is_fork != 'true'
53+
uses: actions/github-script@v7
54+
with:
55+
script: |
56+
const owner = context.repo.owner;
57+
const repo = context.repo.repo;
58+
const shortSha = `${{ steps.short_sha.outputs.sha_short }}`;
59+
const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${{ github.run_id }}`;
60+
const marker = '<!-- docker-build-comment -->';
61+
const registryLink = 'https://console.cloud.google.com/artifacts/docker/robusta-development/us-central1/temporary-builds/robusta-runner?project=robusta-development';
62+
63+
const issue_number = context.payload.pull_request.number;
64+
65+
const existingComments = await github.paginate(github.rest.issues.listComments, {
66+
owner,
67+
repo,
68+
issue_number,
69+
});
70+
const existing = existingComments.find(c => c.body?.includes(marker));
71+
72+
// Clean up old-style comments from previous workflow version
73+
const oldMarker = 'Dev Docker images are ready for this commit:';
74+
const oldComments = existingComments.filter(c => c.body?.includes(oldMarker));
75+
for (const old of oldComments) {
76+
await github.rest.issues.deleteComment({ owner, repo, comment_id: old.id });
77+
core.info(`Deleted old-style comment #${old.id}`);
78+
}
79+
80+
// Extract previous image tag from existing comment if present
81+
let previousImageSection = '';
82+
if (existing) {
83+
const tagMatch = existing.body.match(/robusta-runner:([a-f0-9]{7})/);
84+
if (tagMatch && tagMatch[1] !== shortSha) {
85+
const prevSha = tagMatch[1];
86+
const prevTag = `us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${prevSha}`;
87+
previousImageSection = [
88+
'',
89+
'---',
90+
`📦 **Previous image (\`${prevSha}\`):**`,
91+
`- [${prevTag}](${registryLink})`,
92+
'',
93+
'<details>',
94+
'<summary>📋 Copy commands</summary>',
95+
'',
96+
'⚠️ Temporary images are deleted after 30 days. Copy to a permanent registry before using them:',
97+
'```bash',
98+
'gcloud auth configure-docker us-central1-docker.pkg.dev',
99+
`docker pull ${prevTag}`,
100+
`docker tag ${prevTag} me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${prevSha}`,
101+
`docker push me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${prevSha}`,
102+
'```',
103+
'',
104+
'Patch Helm values in one line:',
105+
'```bash',
106+
'helm upgrade --install robusta robusta/robusta \\\\',
107+
' --reuse-values \\\\',
108+
` --set runner.image=me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${prevSha}`,
109+
'```',
110+
'</details>',
111+
].join('\n');
112+
}
113+
}
114+
115+
const message = [
116+
marker,
117+
`🔨 **Building Docker image for \`${shortSha}\`...** (x64 only)`,
118+
'',
119+
`[View build logs](${runUrl})`,
120+
previousImageSection,
121+
].join('\n');
122+
123+
if (existing) {
124+
await github.rest.issues.updateComment({
125+
owner,
126+
repo,
127+
comment_id: existing.id,
128+
body: message,
129+
});
130+
core.info(`Updated existing PR comment #${existing.id}`);
131+
} else {
132+
await github.rest.issues.createComment({
133+
owner,
134+
repo,
135+
issue_number,
136+
body: message,
137+
});
138+
core.info(`Commented on PR #${issue_number}`);
139+
}
140+
141+
# Registry auth - only for non-fork PRs (fork PRs don't have access to push anyway)
142+
- uses: google-github-actions/auth@v2
143+
if: steps.fork_check.outputs.is_fork != 'true'
144+
with:
145+
project_id: 'robusta-development'
146+
workload_identity_provider: 'projects/479654156100/locations/global/workloadIdentityPools/github/providers/robusta-repos'
147+
148+
- name: Set up gcloud CLI
149+
if: steps.fork_check.outputs.is_fork != 'true'
150+
uses: google-github-actions/setup-gcloud@v2
151+
with:
152+
project_id: robusta-development
153+
154+
- name: Configure Docker Registry
155+
if: steps.fork_check.outputs.is_fork != 'true'
156+
run: gcloud auth configure-docker us-central1-docker.pkg.dev
157+
158+
- name: Set up Docker Buildx
159+
uses: docker/setup-buildx-action@v3
160+
161+
# For fork PRs: build only (no push, no registry tags)
162+
# For non-fork PRs: build and push to registry
163+
# Note: PR builds are x64-only for speed. Multi-arch builds happen on release.
164+
- name: Build Docker image (fork PR - no push)
165+
if: steps.fork_check.outputs.is_fork == 'true'
166+
uses: docker/build-push-action@v6
167+
with:
168+
context: .
169+
platforms: linux/amd64
170+
push: false
171+
cache-from: type=gha
172+
cache-to: type=gha,mode=max
173+
174+
- name: Build and push Docker image
175+
if: steps.fork_check.outputs.is_fork != 'true'
176+
uses: docker/build-push-action@v6
177+
with:
178+
context: .
179+
platforms: linux/amd64
180+
push: true
181+
tags: |
182+
us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${{ github.sha }}
183+
us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${{ steps.short_sha.outputs.sha_short }}
184+
cache-from: type=gha
185+
cache-to: type=gha,mode=max
186+
187+
- name: Print image location
188+
if: steps.fork_check.outputs.is_fork != 'true'
189+
run: |
190+
echo "Docker image pushed (x64 only):"
191+
echo " us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${{ github.sha }}"
192+
echo " us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${{ steps.short_sha.outputs.sha_short }}"
193+
194+
- name: Comment with image details
195+
if: always() && steps.fork_check.outputs.is_fork != 'true'
196+
uses: actions/github-script@v7
197+
with:
198+
script: |
199+
const owner = context.repo.owner;
200+
const repo = context.repo.repo;
201+
const shortSha = `${{ steps.short_sha.outputs.sha_short }}`;
202+
const jobStatus = `${{ job.status }}`;
203+
const runUrl = `https://github.com/${owner}/${repo}/actions/runs/${{ github.run_id }}`;
204+
const marker = '<!-- docker-build-comment -->';
205+
206+
// Calculate build duration
207+
const startTime = parseInt(`${{ steps.start_time.outputs.start }}`);
208+
const endTime = Math.floor(Date.now() / 1000);
209+
const durationSecs = endTime - startTime;
210+
const minutes = Math.floor(durationSecs / 60);
211+
const seconds = durationSecs % 60;
212+
const duration = minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
213+
214+
let message;
215+
if (jobStatus === 'success') {
216+
const shortTag = `us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:${shortSha}`;
217+
const registryLink = 'https://console.cloud.google.com/artifacts/docker/robusta-development/us-central1/temporary-builds/robusta-runner?project=robusta-development';
218+
219+
message = [
220+
marker,
221+
`✅ **Docker image ready for \`${shortSha}\`** (built in ${duration})`,
222+
'',
223+
`- [${shortTag}](${registryLink})`,
224+
'',
225+
'> ⚠️ **Warning: does not support ARM** (ARM images are built on release only - not on every PR)',
226+
'',
227+
'Use this tag to pull the image for testing.',
228+
'',
229+
'<details>',
230+
'<summary>📋 Copy commands</summary>',
231+
'',
232+
'⚠️ Temporary images are deleted after 30 days. Copy to a permanent registry before using them:',
233+
'```bash',
234+
'gcloud auth configure-docker us-central1-docker.pkg.dev',
235+
`docker pull ${shortTag}`,
236+
`docker tag ${shortTag} me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${shortSha}`,
237+
`docker push me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${shortSha}`,
238+
'```',
239+
'',
240+
'Patch Helm values in one line:',
241+
'```bash',
242+
'helm upgrade --install robusta robusta/robusta \\',
243+
' --reuse-values \\',
244+
` --set runner.image=me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:${shortSha}`,
245+
'```',
246+
'</details>',
247+
].join('\n');
248+
} else {
249+
message = [
250+
marker,
251+
`❌ **Docker build failed for \`${shortSha}\`** (after ${duration})`,
252+
'',
253+
`[View build logs](${runUrl})`,
254+
].join('\n');
255+
}
256+
257+
const issue_number = context.payload.pull_request.number;
258+
259+
const existingComments = await github.paginate(github.rest.issues.listComments, {
260+
owner,
261+
repo,
262+
issue_number,
263+
});
264+
const existing = existingComments.find(c => c.body?.includes(marker));
265+
266+
if (existing) {
267+
await github.rest.issues.updateComment({
268+
owner,
269+
repo,
270+
comment_id: existing.id,
271+
body: message,
272+
});
273+
core.info(`Updated existing PR comment #${existing.id}`);
274+
} else {
275+
await github.rest.issues.createComment({
276+
owner,
277+
repo,
278+
issue_number,
279+
body: message,
280+
});
281+
core.info(`Commented on PR #${issue_number}`);
282+
}

.github/workflows/test_robusta.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
name: Test robusta with pytest
22

3-
on: [push, pull_request, workflow_dispatch]
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
workflow_dispatch:
48

59
jobs:
610
check:
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
GCP Cloud Monitoring Integration with Robusta
2+
=============================================
3+
4+
.. note::
5+
This feature is available with the Robusta SaaS platform and self-hosted commercial plans. It is not available in the open-source version.
6+
7+
.. note::
8+
Every alert must carry a ``cluster`` or ``cluster_name`` label. Set it to the Robusta ``cluster_name`` configured for the target cluster, or use ``external`` when the alerts do not belong to a specific runner.
9+
10+
This guide explains how to forward **GCP Cloud Monitoring alerts** to Robusta via a managed notification channel webhook.
11+
12+
Requirements
13+
------------
14+
15+
- Robusta is deployed and running.
16+
- You have access to the Robusta UI (to create an API key and find your ``account_id``).
17+
- You have access to GCP Cloud Monitoring with permissions to create notification channels.
18+
19+
Step 1: Get Robusta Account ID and API Key
20+
------------------------------------------
21+
22+
1. In the Robusta UI, go to **Settings -> API Keys**.
23+
2. Click **New API Key**, select **Alerts: Write** permissions, and **Save**.
24+
3. Copy the generated API key — you will use it as the password for basic authentication.
25+
4. Find your ``account_id``:
26+
27+
- In Robusta, the ``account_id`` appears in your **generated_values.yaml** file (from installation), or
28+
- In the Robusta UI under **Settings -> Workspace**.
29+
30+
Step 2: Create a Webhook Notification Channel in GCP
31+
----------------------------------------------------
32+
33+
1. In the GCP Console, navigate to **Monitoring -> Alerting -> Edit Notification Channels**.
34+
2. Under **Webhooks**, click **Add New**.
35+
3. Configure the webhook with the following settings:
36+
37+
- **Display Name**: ``RobustaWebhook``
38+
- **Endpoint URL**: ``https://api.robusta.dev/integrations/generic/gcp``
39+
- **Authentication**: Select **Basic Authentication**
40+
- **Username**: Your Robusta ``account_id`` from Step 1
41+
- **Password**: Your Robusta API key from Step 1
42+
43+
4. Click **Save** to create the notification channel.
44+
45+
Step 3: Use the Webhook in Alerting Policies
46+
--------------------------------------------
47+
48+
1. Navigate to **Monitoring -> Alerting -> Policies**.
49+
2. Create a new alerting policy or edit an existing one.
50+
3. In the **Notifications** section, select the **RobustaWebhook** notification channel.
51+
4. **Add a cluster label** (required): In the policy's **Documentation** section, add a custom label:
52+
53+
- **Key**: ``cluster_name``
54+
- **Value**: Your Robusta cluster name (e.g., ``my-gcp-cluster``) or ``external`` for non-Kubernetes alerts
55+
56+
5. Save the alerting policy.
57+
58+
Validation
59+
----------
60+
61+
- Trigger a test alert or wait for an existing alerting policy to fire.
62+
- In Robusta's UI, verify the alert appears with the expected details.

0 commit comments

Comments
 (0)