Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a56f738
Migrate test3 to AppDefinition v1beta11 sidecars on clean main-based …
CodeByNikolas Mar 16, 2026
ddd6a0e
ci: bump theia-cloud-crds base version to 1.2.0-next.1
CodeByNikolas Mar 16, 2026
36e2400
ci(test3): override conversion-webhook image to PR build
CodeByNikolas Mar 16, 2026
20d3c61
chore(test3): remove stale pr-46 preloading images
CodeByNikolas Mar 16, 2026
d316777
fix: correct garbage-collector image path to ghcr.io/eduide/garbage-c…
CodeByNikolas Mar 16, 2026
edd722b
Merge branch 'main' into feat/test3-pr70-sidecar-clean
CodeByNikolas Mar 16, 2026
6e19887
fix(test3): align sidecar appdefinitions with reviewer findings
CodeByNikolas Mar 16, 2026
6665fb5
fix(test3): switch no-ls and langserver images to eduide registry
CodeByNikolas Mar 16, 2026
606c591
ci(deploy): tag no-ls and sidecar preloading images with ide_images_tag
CodeByNikolas Mar 16, 2026
6244c38
add conversion images
CodeByNikolas Mar 17, 2026
5d1f00c
conversion webhook
CodeByNikolas Mar 17, 2026
47b5b91
fix(test3): switch operator storageClassName to longhorn for RWX support
CodeByNikolas Mar 17, 2026
f8b91b3
fix(ci): empty tag inputs no longer override values.yaml image settin…
CodeByNikolas Mar 17, 2026
f5205db
fix(ci): empty tag inputs no longer override values.yaml image settings
CodeByNikolas Mar 17, 2026
db17c2b
feat: add 'all' option to workflow_dispatch environment input
CodeByNikolas Mar 17, 2026
5a25db3
fix(test3): use valid operator image path for pr-70 deployments
CodeByNikolas Mar 17, 2026
06092d8
fix(ci): remove environment selector from manual dispatch, always run…
CodeByNikolas Mar 17, 2026
6fbb7fc
Merge remote-tracking branch 'origin/fix/empty-tag-no-override-main-o…
CodeByNikolas Mar 17, 2026
de71aed
update values
CodeByNikolas Mar 17, 2026
29a07ad
fix(test3): pin no-ls and sidecar images to pr-124
CodeByNikolas Mar 17, 2026
2593382
fix(rbac): allow operator to delete sidecar pod collections
CodeByNikolas Mar 17, 2026
a678395
Potential fix for pull request finding
CodeByNikolas Mar 19, 2026
68dd3a6
fix(pr73): v1beta10 lookup fallback, test3 tag alignment, deploy prel…
CodeByNikolas Mar 19, 2026
f393360
feat(ci): add execution_mode dropdown + runner routing, revert v1beta…
CodeByNikolas Mar 19, 2026
60cf941
merge main into PR #73 and keep execution mode + strict migration cho…
CodeByNikolas Mar 19, 2026
49faaef
ci: add runner debug step and adopt sidecar RBAC into Helm
CodeByNikolas Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 35 additions & 26 deletions .github/workflows/deploy-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
# PR Deployment Workflow
# ==============================================================================
# This workflow handles deployments triggered by pull requests and manual
# selections via the GitHub Actions UI.
# dispatch via the GitHub Actions UI.
#
# Manual dispatch (workflow_dispatch) always triggers all three environment
# jobs (test1, test2, test3). Each job is still gated by its own GitHub
# Environment approval before the actual deployment runs.
# ==============================================================================

name: Deploy PR to Environment
Expand All @@ -12,79 +16,84 @@
pull_request:
types: [opened, synchronize, reopened]

# Manual trigger via GitHub UI
# Manual trigger via GitHub UI – always deploys to all three environments.
# Per-environment approvals (configured in GitHub Environment settings) still
# gate each individual job before deployment proceeds.
workflow_dispatch:
inputs:
environment:
description: "Select environment to deploy to"
required: true
type: choice
options:
- test1
- test2
- test3
theia_cloud_tag:
description: 'Theia Cloud components tag (operator, service, landing-page)'
description: 'Theia Cloud components tag (operator, service, landing-page). Leave empty to use the tag defined in values.yaml (no override).'
required: false
default: 'latest'
default: ''
ide_images_tag:
description: 'IDE images tag (appdefinitions and preloading)'
description: 'IDE images tag (appdefinitions and preloading). Leave empty to use the tag defined in values.yaml (no override).'
required: false
default: 'latest'
default: ''
execution_mode:
description: 'Runner backend to use (self-hosted-buildkit or github-runners)'
required: false
default: 'self-hosted-buildkit'
type: choice
options:
- self-hosted-buildkit
- github-runners
helm_chart_tag:
description: 'Preview OCI tag from theia-cloud-helm to use (for example pr-123)'
required: false
default: ''

jobs:
# Job 1: Deploy to Test1 environment
# Runs automatically on all PR events OR when manually selected
# Runs automatically on all PR events OR on any manual dispatch.
# Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings.
# Shared gateway inputs are hardcoded in each job below.
deploy-test1:
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test1')
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
name: Deploy to Test1
uses: ./.github/workflows/deploy-theia.yml
with:
environment: test1
theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }}
ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }}
theia_cloud_tag: ${{ inputs.theia_cloud_tag }}
ide_images_tag: ${{ inputs.ide_images_tag }}
execution_mode: ${{ inputs.execution_mode || 'self-hosted-buildkit' }}
helm_chart_tag: ${{ inputs.helm_chart_tag || '' }}
deploy_shared_gateway: false

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
shared_gateway_values_file: deployments/shared-gateway/values.yaml
shared_gateway_namespace: gateway-system
secrets: inherit

# Job 2: Deploy to Test2 environment
# Runs automatically on all PR events OR when manually selected
# Runs automatically on all PR events OR on any manual dispatch.
# Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings.
# Shared gateway inputs are hardcoded in each job below.
deploy-test2:
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test2')
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
name: Deploy to Test2
uses: ./.github/workflows/deploy-theia.yml
with:
environment: test2
theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }}
ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }}
theia_cloud_tag: ${{ inputs.theia_cloud_tag }}
ide_images_tag: ${{ inputs.ide_images_tag }}
execution_mode: ${{ inputs.execution_mode || 'self-hosted-buildkit' }}
helm_chart_tag: ${{ inputs.helm_chart_tag || '' }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
deploy_shared_gateway: false
shared_gateway_values_file: deployments/shared-gateway/values.yaml
shared_gateway_namespace: gateway-system
secrets: inherit

# Job 3: Deploy to Test3 environment
# Runs automatically on all PR events OR when manually selected
# Runs automatically on all PR events OR on any manual dispatch.
# Environment variables NAMESPACE and HELM_VALUES_PATH are read from GitHub Environment settings.
# Shared gateway inputs are hardcoded in each job below.
deploy-test3:
if: github.event_name == 'pull_request' || (github.event_name == 'workflow_dispatch' && inputs.environment == 'test3')
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
name: Deploy to Test3

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
uses: ./.github/workflows/deploy-theia.yml
with:
environment: test3
theia_cloud_tag: ${{ inputs.theia_cloud_tag || 'latest' }}
ide_images_tag: ${{ inputs.ide_images_tag || 'latest' }}
theia_cloud_tag: ${{ inputs.theia_cloud_tag }}
ide_images_tag: ${{ inputs.ide_images_tag }}
execution_mode: ${{ inputs.execution_mode || 'self-hosted-buildkit' }}
helm_chart_tag: ${{ inputs.helm_chart_tag || '' }}
deploy_shared_gateway: false
shared_gateway_values_file: deployments/shared-gateway/values.yaml
Expand Down
79 changes: 53 additions & 26 deletions .github/workflows/deploy-theia.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ on:
required: true
type: string
theia_cloud_tag:
description: "Image tag for Theia Cloud components (operator, service, landing-page)"
description: "Image tag for Theia Cloud components (operator, service, landing-page). Leave empty to use the tag defined in values.yaml (no override)."
required: false
type: string
default: "latest"
default: ""
ide_images_tag:
description: "Image tag for IDE images (appdefinitions and preloading)"
description: "Image tag for IDE images (appdefinitions and preloading). Leave empty to use the tag defined in values.yaml (no override)."
required: false
type: string
default: "latest"
default: ""
helm_chart_tag:
description: "Published OCI preview tag to use for upstream helm charts (e.g. pr-123)"
required: false
Expand All @@ -75,14 +75,19 @@ on:
required: false
type: string
default: "gateway-system"
execution_mode:
description: "Runner backend to use (self-hosted-buildkit or github-runners)"
required: false
type: string
default: "self-hosted-buildkit"

jobs:
helm-install:
name: Install Theia Cloud Helm Chart
permissions:
contents: read
packages: read
runs-on: ubuntu-latest
runs-on: ${{ inputs.execution_mode == 'github-runners' && 'ubuntu-latest' || 'arc-buildkit-eduide-amd64' }}
# Link to GitHub Environment for secrets and protection rules
environment: ${{ inputs.environment }}

Expand Down Expand Up @@ -162,7 +167,7 @@ jobs:
set -euo pipefail

THEIA_CLOUD_BASE_VERSION="1.4.0-next.0"
THEIA_CLOUD_CRDS_VERSION="1.2.0-next.0"
THEIA_CLOUD_CRDS_VERSION="1.2.0-next.1"

if [ -n "${{ inputs.helm_chart_tag }}" ]; then
normalize_preview_version() {
Expand Down Expand Up @@ -219,6 +224,8 @@ jobs:
env:
KUBECONFIG: ${{ github.workspace }}/kubeconfig
run: |
set -euo pipefail

# Prepare SSL certificates for ingress
# Note: Secrets are already base64 encoded, but we need to write them to files
echo "${{ secrets.THEIA_WILDCARD_CERTIFICATE_CERT }}" | base64 -w 0 > wildcard.crt
Expand All @@ -229,26 +236,46 @@ jobs:
THEIA_CLOUD_TAG="${{ inputs.theia_cloud_tag }}"
IDE_IMAGES_TAG="${{ inputs.ide_images_tag }}"

# Build base helm command with always-present flags
HELM_CMD=(helm upgrade --install theia-cloud-combined ./charts/theia-cloud-combined
--namespace ${{ vars.NAMESPACE }}
--create-namespace
-f ${{ vars.HELM_VALUES_PATH }}/values.yaml
--set-string theia-certificates.adminApiToken="${ADMIN_API_TOKEN_B64}"
--set theia-certificates.wildcardCertificate="$(cat wildcard.crt)"
--set theia-certificates.wildcardKey="$(cat wildcard.key)"
--set theia-cloud.keycloak.cookieSecret="${{ secrets.THEIA_KEYCLOAK_COOKIE_SECRET }}")

# Only override Theia Cloud component images when a tag is explicitly provided
if [ -n "${THEIA_CLOUD_TAG}" ]; then
HELM_CMD+=(
--set theia-cloud.landingPage.image="ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}"
--set theia-cloud.operator.image="ghcr.io/eduide/eduide-cloud/operator:${THEIA_CLOUD_TAG}"
--set theia-cloud.service.image="ghcr.io/eduide/eduide-cloud/service:${THEIA_CLOUD_TAG}"
--set "theia-cloud.preloading.images[0]=ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}"
)
fi

# Only override IDE images when a tag is explicitly provided
if [ -n "${IDE_IMAGES_TAG}" ]; then
HELM_CMD+=(
--set "theia-cloud.preloading.images[1]=ghcr.io/eduide/eduide/java-17:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[2]=ghcr.io/eduide/eduide/c:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[3]=ghcr.io/eduide/eduide/javascript:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[4]=ghcr.io/eduide/eduide/ocaml:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[5]=ghcr.io/eduide/eduide/rust:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[6]=ghcr.io/eduide/eduide/python:${IDE_IMAGES_TAG}"
# Intentionally override no-ls + langserver preload images globally when IDE tag is overridden.
--set "theia-cloud.preloading.images[7]=ghcr.io/eduide/eduide/java-17-no-ls:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[8]=ghcr.io/eduide/eduide/rust-no-ls:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[9]=ghcr.io/eduide/eduide/langserver-java:${IDE_IMAGES_TAG}"
--set "theia-cloud.preloading.images[10]=ghcr.io/eduide/eduide/langserver-rust:${IDE_IMAGES_TAG}"
--set theia-appdefinitions.defaultImageTag="${IDE_IMAGES_TAG}"
)
fi

# Install/upgrade the Helm chart with all configuration
# --install: Create if it doesn't exist, upgrade if it does
# --create-namespace: Create the namespace if it doesn't exist
# Image tags controlled by two variables: THEIA_CLOUD_TAG and IDE_IMAGES_TAG
helm upgrade --install theia-cloud-combined ./charts/theia-cloud-combined \
--namespace ${{ vars.NAMESPACE }} \
--create-namespace \
-f ${{ vars.HELM_VALUES_PATH }}/values.yaml \
--set-string theia-certificates.adminApiToken="${ADMIN_API_TOKEN_B64}" \
--set theia-certificates.wildcardCertificate="$(cat wildcard.crt)" \
--set theia-certificates.wildcardKey="$(cat wildcard.key)" \
--set theia-cloud.keycloak.cookieSecret="${{ secrets.THEIA_KEYCLOAK_COOKIE_SECRET }}" \
--set theia-cloud.landingPage.image="ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" \
--set theia-cloud.operator.image="ghcr.io/eduide/eduide-cloud/operator:${THEIA_CLOUD_TAG}" \
--set theia-cloud.service.image="ghcr.io/eduide/eduide-cloud/service:${THEIA_CLOUD_TAG}" \
--set "theia-cloud.preloading.images[0]=ghcr.io/eduide/eduide-cloud/landing-page:${THEIA_CLOUD_TAG}" \
--set "theia-cloud.preloading.images[1]=ghcr.io/eduide/eduide/java-17:${IDE_IMAGES_TAG}" \
--set "theia-cloud.preloading.images[2]=ghcr.io/eduide/eduide/c:${IDE_IMAGES_TAG}" \
--set "theia-cloud.preloading.images[3]=ghcr.io/eduide/eduide/javascript:${IDE_IMAGES_TAG}" \
--set "theia-cloud.preloading.images[4]=ghcr.io/eduide/eduide/ocaml:${IDE_IMAGES_TAG}" \
--set "theia-cloud.preloading.images[5]=ghcr.io/eduide/eduide/rust:${IDE_IMAGES_TAG}" \
--set "theia-cloud.preloading.images[6]=ghcr.io/eduide/eduide/python:${IDE_IMAGES_TAG}" \
--set theia-appdefinitions.defaultImageTag="${IDE_IMAGES_TAG}"
# Image tag overrides are applied only when non-empty; otherwise values.yaml settings are preserved
"${HELM_CMD[@]}"
40 changes: 38 additions & 2 deletions charts/theia-appdefinitions/templates/appdefinition.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{- range .Values.apps }}
{{- $existingApp := lookup "theia.cloud/v1beta10" "AppDefinition" $.Release.Namespace .name }}
{{- $existingApp := lookup "theia.cloud/v1beta11" "AppDefinition" $.Release.Namespace .name }}
{{- $existingSpec := dict }}
{{- if $existingApp }}
{{- $existingSpec = get $existingApp "spec" | default dict }}
Expand All @@ -14,7 +14,7 @@
{{- $maxInstances = get $existingSpec "maxInstances" }}
{{- end }}
---
apiVersion: theia.cloud/v1beta10
apiVersion: theia.cloud/v1beta11
kind: AppDefinition
metadata:
name: {{ .name }}
Expand Down Expand Up @@ -54,4 +54,40 @@ spec:
options:
{{- toYaml .options | nindent 4 }}
{{- end }}
{{- if .sidecars }}
sidecars:
{{- range .sidecars }}
- name: {{ .name }}
{{- $sidecarImage := .image }}
{{- if or (contains "@sha256:" $sidecarImage) (regexMatch ".*:[^/]+$" $sidecarImage) }}
image: {{ $sidecarImage }}
{{- else }}
image: {{ $sidecarImage }}:{{ .imageTag | default $.Values.defaultImageTag | default "latest" }}
{{- end }}
port: {{ .port | default 5000 }}
{{- if .languages }}
languages:
{{- range .languages }}
- {{ . }}
{{- end }}
{{- end }}
{{- if .cpuLimit }}
cpuLimit: {{ .cpuLimit }}
{{- end }}
{{- if .memoryLimit }}
memoryLimit: {{ .memoryLimit }}
{{- end }}
{{- if .cpuRequest }}
cpuRequest: {{ .cpuRequest }}
{{- end }}
{{- if .memoryRequest }}
memoryRequest: {{ .memoryRequest }}
{{- end }}
{{- if hasKey . "mountWorkspace" }}
mountWorkspace: {{ .mountWorkspace }}
{{- else }}
mountWorkspace: true
{{- end }}
{{- end }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operator-sidecar-pod-restart
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/managed-by: Helm
rules:
- apiGroups: [""]
resources: ["pods"]
# deletecollection is intentionally kept for batch sidecar-pod restart cleanup operations.
verbs: ["get", "list", "watch", "delete", "deletecollection"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: operator-sidecar-pod-restart
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/managed-by: Helm
subjects:
- kind: ServiceAccount
name: operator-api-service-account
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: operator-sidecar-pod-restart
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# -- The cluster issuer to use for the certificate
clusterIssuer: theia-cloud-selfsigned-issuer

conversion:
image: ghcr.io/eduide/eduide-cloud/conversion-webhook:pr-70
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# -- The cluster issuer to use for the certificate
clusterIssuer: theia-cloud-selfsigned-issuer

conversion:
image: ghcr.io/eduide/eduide-cloud/conversion-webhook:pr-70
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# -- The cluster issuer to use for the certificate
# Name of the cert-manager ClusterIssuer used to issue TLS certificates for this deployment.
clusterIssuer: theia-cloud-selfsigned-issuer

conversion:
image: ghcr.io/eduide/eduide-cloud/conversion-webhook:pr-70
Loading
Loading