Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ uses: qBraid/upload-course-action@v0.1.0-beta
- Fixed JSend response parsing in deploy and polling scripts to support `{status, data}` envelope format
- Added guard in `action.yml` to fail early with a clear error when `course_custom_id` is empty after create/update step
- Replaced silent `pass` with warning logs when API response parsing fails
- Failed kernel deployment polling immediately on terminal API errors instead of retrying until timeout
- Made the deploy-kernel wrapper reuse the shared Dockerfile validator implementation

### Changed
- Treat active pre-existing kernels as a successful deploy outcome for rerun-safe custom kernel workflows

### Added
- Unit tests for JSend response handling in course creation and polling
Expand Down
87 changes: 87 additions & 0 deletions deploy-kernel/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: 'Deploy Custom Kernel to qBraid'
description: 'Validates and deploys a custom Jupyter kernel image to qBraid qBook'
author: 'qBraid'

branding:
icon: 'cpu'
color: 'purple'

inputs:
api-key:
description: 'qBraid API key for authentication'
required: true
dockerfile-path:
description: 'Path to the kernel Dockerfile'
required: false
default: 'Dockerfile.kernel'
kernel-name:
description: 'Unique kernel name (lowercase alphanumeric + underscore, 3-64 chars)'
required: true
language:
description: 'Kernel language (python, cpp, julia, r, rust, go, javascript)'
required: true
display-name:
description: 'Human-readable display name for the kernel'
required: true
context-dir:
description: 'Directory containing additional build context files (requirements.txt, kernel.json, etc.)'
required: false
default: '.'
api-base-url:
description: 'qBraid API base URL'
required: false
default: 'https://api-v2.qbraid.com/api/v1'
timeout-seconds:
description: 'Maximum time to wait for deployment to finish'
required: false
default: '1800'

outputs:
kernel-name:
description: 'The deployed kernel name'
value: ${{ steps.deploy-kernel.outputs.kernel-name }}
image-uri:
description: 'The Artifact Registry image URI'
value: ${{ steps.deploy-kernel.outputs.image-uri }}
status:
description: 'Deployment status (active, failed, timeout)'
value: ${{ steps.deploy-kernel.outputs.status }}
build-id:
description: 'Cloud Build ID'
value: ${{ steps.deploy-kernel.outputs.build-id }}

runs:
using: 'composite'
steps:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
shell: bash
run: |
python -m pip install -q -r "${{ github.action_path }}/requirements.txt"

- name: Validate Dockerfile
shell: bash
run: |
python ${{ github.action_path }}/src/scripts/validate_dockerfile.py \
"${{ inputs.dockerfile-path }}"

- name: Deploy kernel
id: deploy-kernel
shell: bash
env:
QBRAID_API_KEY: ${{ inputs.api-key }}
QBRAID_DEPLOY_TIMEOUT_SECONDS: ${{ inputs.timeout-seconds }}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composite action exports QBRAID_DEPLOY_TIMEOUT_SECONDS, but deploy_kernel.py doesn't read this environment variable (timeout is passed via --timeout-seconds). This extra env var can confuse users—either remove it or wire the script to honor it when the CLI arg isn't provided.

Suggested change
QBRAID_DEPLOY_TIMEOUT_SECONDS: ${{ inputs.timeout-seconds }}

Copilot uses AI. Check for mistakes.
run: |
echo "::add-mask::$QBRAID_API_KEY"
python ${{ github.action_path }}/src/scripts/deploy_kernel.py \
--dockerfile-path "${{ inputs.dockerfile-path }}" \
--kernel-name "${{ inputs.kernel-name }}" \
--language "${{ inputs.language }}" \
--display-name "${{ inputs.display-name }}" \
--context-dir "${{ inputs.context-dir }}" \
--api-base-url "${{ inputs.api-base-url }}" \
--timeout-seconds "${{ inputs.timeout-seconds }}"
1 change: 1 addition & 0 deletions deploy-kernel/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
requests>=2.31.0
Loading
Loading