Skip to content

Commit 805eae7

Browse files
fix(webapp): resolve merge conflicts in RunPresenter.server.ts
2 parents 960b23f + 4dc504d commit 805eae7

File tree

100 files changed

+7785
-1083
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+7785
-1083
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: 🧭 Helm Chart PR Prerelease
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
- "hosting/k8s/helm/**"
8+
9+
concurrency:
10+
group: helm-prerelease-${{ github.event.pull_request.number }}
11+
cancel-in-progress: true
12+
13+
env:
14+
REGISTRY: ghcr.io
15+
CHART_NAME: trigger
16+
17+
jobs:
18+
lint-and-test:
19+
runs-on: ubuntu-latest
20+
permissions:
21+
contents: read
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Set up Helm
27+
uses: azure/setup-helm@v4
28+
with:
29+
version: "3.18.3"
30+
31+
- name: Build dependencies
32+
run: helm dependency build ./hosting/k8s/helm/
33+
34+
- name: Extract dependency charts
35+
run: |
36+
cd ./hosting/k8s/helm/
37+
for file in ./charts/*.tgz; do echo "Extracting $file"; tar -xzf "$file" -C ./charts; done
38+
39+
- name: Lint Helm Chart
40+
run: |
41+
helm lint ./hosting/k8s/helm/
42+
43+
- name: Render templates
44+
run: |
45+
helm template test-release ./hosting/k8s/helm/ \
46+
--values ./hosting/k8s/helm/values.yaml \
47+
--output-dir ./helm-output
48+
49+
- name: Validate manifests
50+
uses: docker://ghcr.io/yannh/kubeconform:v0.7.0
51+
with:
52+
entrypoint: "/kubeconform"
53+
args: "-summary -output json ./helm-output"
54+
55+
prerelease:
56+
needs: lint-and-test
57+
runs-on: ubuntu-latest
58+
permissions:
59+
contents: read
60+
packages: write
61+
pull-requests: write
62+
steps:
63+
- name: Checkout
64+
uses: actions/checkout@v4
65+
66+
- name: Set up Helm
67+
uses: azure/setup-helm@v4
68+
with:
69+
version: "3.18.3"
70+
71+
- name: Build dependencies
72+
run: helm dependency build ./hosting/k8s/helm/
73+
74+
- name: Extract dependency charts
75+
run: |
76+
cd ./hosting/k8s/helm/
77+
for file in ./charts/*.tgz; do echo "Extracting $file"; tar -xzf "$file" -C ./charts; done
78+
79+
- name: Log in to Container Registry
80+
uses: docker/login-action@v3
81+
with:
82+
registry: ${{ env.REGISTRY }}
83+
username: ${{ github.actor }}
84+
password: ${{ secrets.GITHUB_TOKEN }}
85+
86+
- name: Generate prerelease version
87+
id: version
88+
run: |
89+
BASE_VERSION=$(grep '^version:' ./hosting/k8s/helm/Chart.yaml | awk '{print $2}')
90+
PR_NUMBER=${{ github.event.pull_request.number }}
91+
SHORT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-7)
92+
PRERELEASE_VERSION="${BASE_VERSION}-pr${PR_NUMBER}.${SHORT_SHA}"
93+
echo "version=$PRERELEASE_VERSION" >> $GITHUB_OUTPUT
94+
echo "Prerelease version: $PRERELEASE_VERSION"
95+
96+
- name: Update Chart.yaml with prerelease version
97+
run: |
98+
sed -i "s/^version:.*/version: ${{ steps.version.outputs.version }}/" ./hosting/k8s/helm/Chart.yaml
99+
100+
- name: Package Helm Chart
101+
run: |
102+
helm package ./hosting/k8s/helm/ --destination /tmp/
103+
104+
- name: Push Helm Chart to GHCR
105+
run: |
106+
VERSION="${{ steps.version.outputs.version }}"
107+
CHART_PACKAGE="/tmp/${{ env.CHART_NAME }}-${VERSION}.tgz"
108+
109+
# Push to GHCR OCI registry
110+
helm push "$CHART_PACKAGE" "oci://${{ env.REGISTRY }}/${{ github.repository_owner }}/charts"
111+
112+
- name: Find existing comment
113+
uses: peter-evans/find-comment@v3
114+
id: find-comment
115+
with:
116+
issue-number: ${{ github.event.pull_request.number }}
117+
comment-author: "github-actions[bot]"
118+
body-includes: "Helm Chart Prerelease Published"
119+
120+
- name: Create or update PR comment
121+
uses: peter-evans/create-or-update-comment@v4
122+
with:
123+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
124+
issue-number: ${{ github.event.pull_request.number }}
125+
body: |
126+
### 🧭 Helm Chart Prerelease Published
127+
128+
**Version:** `${{ steps.version.outputs.version }}`
129+
130+
**Install:**
131+
```bash
132+
helm upgrade --install trigger \
133+
oci://ghcr.io/${{ github.repository_owner }}/charts/trigger \
134+
--version "${{ steps.version.outputs.version }}"
135+
```
136+
137+
> ⚠️ This is a prerelease for testing. Do not use in production.
138+
edit-mode: replace

apps/supervisor/src/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const Env = z.object({
9191
KUBERNETES_MEMORY_REQUEST_RATIO: z.coerce.number().min(0).max(1).default(1), // Ratio of memory limit, so 1 = 100% of memory limit
9292
KUBERNETES_MEMORY_OVERHEAD_GB: z.coerce.number().min(0).optional(), // Optional memory overhead to add to the limit in GB
9393
KUBERNETES_SCHEDULER_NAME: z.string().optional(), // Custom scheduler name for pods
94+
KUBERNETES_LARGE_MACHINE_POOL_LABEL: z.string().optional(), // if set, large-* presets affinity for machinepool=<value>
9495

9596
// Placement tags settings
9697
PLACEMENT_TAGS_ENABLED: BoolEnv.default(false),

apps/supervisor/src/workloadManager/kubernetes.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
9595
},
9696
spec: {
9797
...this.addPlacementTags(this.#defaultPodSpec, opts.placementTags),
98+
affinity: this.#getNodeAffinity(opts.machine),
9899
terminationGracePeriodSeconds: 60 * 60,
99100
containers: [
100101
{
@@ -356,4 +357,55 @@ export class KubernetesWorkloadManager implements WorkloadManager {
356357
},
357358
};
358359
}
360+
361+
#isLargeMachine(preset: MachinePreset): boolean {
362+
return preset.name.startsWith("large-");
363+
}
364+
365+
#getNodeAffinity(preset: MachinePreset): k8s.V1Affinity | undefined {
366+
if (!env.KUBERNETES_LARGE_MACHINE_POOL_LABEL) {
367+
return undefined;
368+
}
369+
370+
if (this.#isLargeMachine(preset)) {
371+
// soft preference for the large-machine pool, falls back to standard if unavailable
372+
return {
373+
nodeAffinity: {
374+
preferredDuringSchedulingIgnoredDuringExecution: [
375+
{
376+
weight: 100,
377+
preference: {
378+
matchExpressions: [
379+
{
380+
key: "node.cluster.x-k8s.io/machinepool",
381+
operator: "In",
382+
values: [env.KUBERNETES_LARGE_MACHINE_POOL_LABEL],
383+
},
384+
],
385+
},
386+
},
387+
],
388+
},
389+
};
390+
}
391+
392+
// not schedulable in the large-machine pool
393+
return {
394+
nodeAffinity: {
395+
requiredDuringSchedulingIgnoredDuringExecution: {
396+
nodeSelectorTerms: [
397+
{
398+
matchExpressions: [
399+
{
400+
key: "node.cluster.x-k8s.io/machinepool",
401+
operator: "NotIn",
402+
values: [env.KUBERNETES_LARGE_MACHINE_POOL_LABEL],
403+
},
404+
],
405+
},
406+
],
407+
},
408+
},
409+
};
410+
}
359411
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
export function LogsIcon({ className }: { className?: string }) {
2+
return (
3+
<svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
4+
<circle cx="4" cy="10" r="1" fill="currentColor" />
5+
<circle cx="4" cy="5" r="1" fill="currentColor" />
6+
<circle cx="4" cy="14" r="1" fill="currentColor" />
7+
<circle cx="4" cy="19" r="1" fill="currentColor" />
8+
<path
9+
d="M7 9.75L10 9.75"
10+
stroke="currentColor"
11+
strokeWidth="2"
12+
strokeLinecap="round"
13+
strokeLinejoin="round"
14+
/>
15+
<path
16+
d="M7 5L10 5"
17+
stroke="currentColor"
18+
strokeWidth="2"
19+
strokeLinecap="round"
20+
strokeLinejoin="round"
21+
/>
22+
<path
23+
d="M7 14.25H10"
24+
stroke="currentColor"
25+
strokeWidth="2"
26+
strokeLinecap="round"
27+
strokeLinejoin="round"
28+
/>
29+
<path
30+
d="M7 19H10"
31+
stroke="currentColor"
32+
strokeWidth="2"
33+
strokeLinecap="round"
34+
strokeLinejoin="round"
35+
/>
36+
<path
37+
d="M13 5H20"
38+
stroke="currentColor"
39+
strokeWidth="2"
40+
strokeLinecap="round"
41+
strokeLinejoin="round"
42+
/>
43+
<path
44+
d="M13 9.75H20"
45+
stroke="currentColor"
46+
strokeWidth="2"
47+
strokeLinecap="round"
48+
strokeLinejoin="round"
49+
/>
50+
<path
51+
d="M13 14.25H20"
52+
stroke="currentColor"
53+
strokeWidth="2"
54+
strokeLinecap="round"
55+
strokeLinejoin="round"
56+
/>
57+
<path
58+
d="M13 19H20"
59+
stroke="currentColor"
60+
strokeWidth="2"
61+
strokeLinecap="round"
62+
strokeLinejoin="round"
63+
/>
64+
</svg>
65+
);
66+
}

apps/webapp/app/components/code/AIQueryInput.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ interface AIQueryInputProps {
3232
onQueryGenerated: (query: string) => void;
3333
/** Set this to a prompt to auto-populate and immediately submit */
3434
autoSubmitPrompt?: string;
35+
/** Change this to force re-submission even if prompt is the same */
36+
autoSubmitKey?: number;
3537
/** Get the current query in the editor (used for edit mode) */
3638
getCurrentQuery?: () => string;
3739
}
3840

3941
export function AIQueryInput({
4042
onQueryGenerated,
4143
autoSubmitPrompt,
44+
autoSubmitKey,
4245
getCurrentQuery,
4346
}: AIQueryInputProps) {
4447
const [prompt, setPrompt] = useState("");
@@ -50,7 +53,7 @@ export function AIQueryInput({
5053
const [lastResult, setLastResult] = useState<"success" | "error" | null>(null);
5154
const textareaRef = useRef<HTMLTextAreaElement>(null);
5255
const abortControllerRef = useRef<AbortController | null>(null);
53-
const lastAutoSubmitRef = useRef<string | null>(null);
56+
const lastAutoSubmitRef = useRef<{ prompt: string; key?: number } | null>(null);
5457

5558
const organization = useOrganization();
5659
const project = useProject();
@@ -197,19 +200,22 @@ export function AIQueryInput({
197200
[prompt, submitQuery]
198201
);
199202

200-
// Auto-submit when autoSubmitPrompt changes
203+
// Auto-submit when autoSubmitPrompt or autoSubmitKey changes
201204
useEffect(() => {
202-
if (
203-
autoSubmitPrompt &&
204-
autoSubmitPrompt.trim() &&
205-
autoSubmitPrompt !== lastAutoSubmitRef.current &&
206-
!isLoading
207-
) {
208-
lastAutoSubmitRef.current = autoSubmitPrompt;
205+
if (!autoSubmitPrompt || !autoSubmitPrompt.trim() || isLoading) {
206+
return;
207+
}
208+
209+
const last = lastAutoSubmitRef.current;
210+
const isDifferent =
211+
last === null || autoSubmitPrompt !== last.prompt || autoSubmitKey !== last.key;
212+
213+
if (isDifferent) {
214+
lastAutoSubmitRef.current = { prompt: autoSubmitPrompt, key: autoSubmitKey };
209215
setPrompt(autoSubmitPrompt);
210216
submitQuery(autoSubmitPrompt);
211217
}
212-
}, [autoSubmitPrompt, isLoading, submitQuery]);
218+
}, [autoSubmitPrompt, autoSubmitKey, isLoading, submitQuery]);
213219

214220
// Cleanup on unmount
215221
useEffect(() => {

0 commit comments

Comments
 (0)