Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
837851f
chore: add source repo cleaning mechanism for git clone
Zaperex Feb 6, 2026
b9c7fc5
chore: add unit tests for --clean logic
Zaperex Feb 6, 2026
95cbac6
chore: split existing unit test files into smaller files for maintain…
Zaperex Feb 6, 2026
0030e28
chore: refactor error handling
Zaperex Feb 9, 2026
84901b3
chore: refactor to move validation into __post_init__ functions
Zaperex Feb 9, 2026
1dcbbbb
feat: add CLI option to define source repo and ref
Zaperex Feb 17, 2026
8149808
feat: add multi-workspace support
Zaperex Mar 10, 2026
ffc6519
feat: add initial basic plugins-list.yaml generation
Zaperex Mar 10, 2026
4ba59bf
chore: update version argument to return script and yarn lock commit …
Zaperex Mar 6, 2026
86fc972
feat: add initial plugins-list.yaml auto generate
Zaperex Mar 10, 2026
ac0eaa7
chore: add granular build arg generation
Zaperex Mar 10, 2026
c7c837d
chore: split config file and refactor constants
Zaperex Mar 10, 2026
6ad7484
chore: add plugin build arg generation unit tests
Zaperex Mar 10, 2026
2f31ad7
chore: scan more than one layer of dep for backstage deps
Zaperex Mar 10, 2026
81e0fe3
docs: add plugins-list.yaml auto-gen docs
Zaperex Mar 11, 2026
c408140
chore: fix mypy errors
Zaperex Mar 11, 2026
0092226
chore: cache host yarn.lock dep load
Zaperex Mar 11, 2026
c5125c9
chore: update unit tests
Zaperex Mar 11, 2026
e77b6e6
chore: update troubleshooting docs with special edge case for native …
Zaperex Mar 11, 2026
d1e3ae3
chore: update troubleshooting docs to share package instead of allowi…
Zaperex Mar 12, 2026
30aa937
chore: handle single directory workspace corner case
Zaperex Mar 13, 2026
ab84357
chore: add initial e2e integration tests
Zaperex Mar 13, 2026
3625ac9
chore: update skip action to be incremental and build for e2e tests
Zaperex Mar 13, 2026
d0a4d31
chore: fix pr resolution in e2e-test workflow
Zaperex Mar 13, 2026
5662ead
chore: add more traceability for the e2e test workflow
Zaperex Mar 16, 2026
51188c1
chore: properly checkout the correct branch for e2e-tests
Zaperex Mar 16, 2026
e2e8bb2
chore: update .gitignore to not ignore fixtures
Zaperex Mar 16, 2026
b7fc64f
chore: fix typo in docs
Zaperex Mar 16, 2026
f9b301e
chore: update auto-gen logic to create barebones plugins-list.yaml fo…
Zaperex Mar 16, 2026
16bbb94
chore: add warning when using --env-file podman arg
Zaperex Mar 16, 2026
b43c1e5
chore: update to use latest rhdh-cli by default
Zaperex Mar 18, 2026
15cb185
chore: surface native dep yarn build logs
Zaperex Mar 23, 2026
f99fe07
chore: fix typos
Zaperex Apr 1, 2026
bf72433
chore: add support for auth.json authentication
Zaperex Apr 7, 2026
a95c640
chore: remove dup logs
Zaperex Apr 8, 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
7 changes: 7 additions & 0 deletions .cursor/rules/development-workflow.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ description: Development workflow commands and processes for the rhdh-dynamic-pl
globs:
alwaysApply: true
---

## Dependency Management

When adding new Python dependencies:
1. Install using the `.venv` virtual environment: `.venv/bin/pip install <package>`
2. Update `requirements.txt` (runtime deps) or `requirements.dev.txt` (dev/test deps) to reflect the change
3. Verify the installed version matches what is recorded in the requirements file
2 changes: 1 addition & 1 deletion .cursor/rules/integration-tests.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_full_config_flow(self, make_config):

## Container E2E Tests

> **Note:** E2E tests are not yet implemented. The `tests/e2e/` directory does not exist. The following guidance is for future implementation.
> E2E tests are implemented in `tests/e2e/`. The `E2E_IMAGE` env var is **required** (no default fallback).

- **Location**: `tests/e2e/`.
- **Goal**: Validate that the container image works correctly with the provided `examples/`.
Expand Down
10 changes: 7 additions & 3 deletions .cursor/rules/pytest-unit-tests.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ globs: tests/test_*.py
## General Principles
- All unit tests must reside in the `tests/` directory.
- Use **class-based grouping** for tests (e.g., `class TestClassName:`).
- One test file per module (e.g., `test_config.py` for `config.py`).
- One test file per class or method group. For small modules, use `test_<module>.py`. When tests exceed ~300-400 lines, split into `test_<module>_<method_or_class>.py`.
- Ensure **100% isolation**: No network calls, no real file system changes outside `tmp_path`, no system command execution.

## Test Structure
Expand Down Expand Up @@ -81,11 +81,15 @@ def test_with_registry_config(self, make_config):
```

## Naming Conventions
- Files: `test_<module_name>.py`
- Files: `test_<module_name>.py` for small modules, or `test_<module_name>_<method_or_class>.py` when a module's tests exceed ~300-400 lines
- Classes: `Test<ClassName><MethodName>` (optional MethodName if grouping by method)
- Functions: `test_<scenario_description>`

## Current Test Files
- `test_config.py`: Tests for `PluginFactoryConfig` class (load_from_env, load_registry_config, apply_patches_and_overlays, export_plugins)
- `test_cli.py`: Tests for CLI argument parsing (`create_parser`)
- `test_config_load_from_env.py`: Tests for `PluginFactoryConfig.load_from_env` method
- `test_config_registry.py`: Tests for `PluginFactoryConfig.load_registry_config` method
- `test_config_patches_and_overlays.py`: Tests for `PluginFactoryConfig.apply_patches_and_overlays` method
- `test_config_export_plugins.py`: Tests for `PluginFactoryConfig.export_plugins` method
- `test_source_config.py`: Tests for `SourceConfig` class (from_file, clone_to_path)
- `test_plugin_list_config.py`: Tests for `PluginListConfig` class (from_file, get_plugins, add_plugin, remove_plugin)
60 changes: 52 additions & 8 deletions .github/actions/should-skip-build/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ inputs:
description: 'Regex patterns to match files for skip logic (space, comma, or newline-separated)'
required: false
default: '\.md$'
pr-number:
description: 'PR number for first-build protection. When set, skips only if a pr-{number} image already exists in the registry.'
required: false
default: ''
outputs:
should_skip:
description: 'Whether the build should be skipped (true/false)'
Expand All @@ -29,7 +33,7 @@ runs:
using: 'composite'
steps:
- name: Install skopeo
if: inputs.check-image == 'true'
if: inputs.check-image == 'true' || inputs.pr-number != ''
shell: bash
run: |
if ! command -v skopeo &> /dev/null; then
Expand Down Expand Up @@ -93,13 +97,26 @@ runs:
;;

pull_request|pull_request_target)
echo "Pull request event detected"
if [ -n "${{ github.event.pull_request.base.sha }}" ]; then
# Find the merge base between PR base and HEAD
echo "Pull request event detected (action: ${{ github.event.action }})"

# For synchronize events, use incremental diff (since last push)
# to avoid rebuilding for non-build affecting commits in a PR.
# Fall back to full PR diff for opened/reopened or if incremental fails.
if [ "${{ github.event.action }}" = "synchronize" ] && [ -n "${{ github.event.before }}" ]; then
BEFORE_SHA="${{ github.event.before }}"
echo "Synchronize event — attempting incremental diff against previous HEAD: ${BEFORE_SHA}"
if CHANGED_FILES=$(git diff --name-only "${BEFORE_SHA}" HEAD 2>/dev/null); then
echo "Using incremental diff (since last push)"
else
echo "Warning: incremental diff failed (before SHA unreachable), falling back to full PR diff"
BASE_COMMIT=$(git merge-base ${{ github.event.pull_request.base.sha }} HEAD)
echo "Base commit (merge-base): $BASE_COMMIT"
CHANGED_FILES=$(git diff --name-only "$BASE_COMMIT" HEAD)
fi
elif [ -n "${{ github.event.pull_request.base.sha }}" ]; then
BASE_COMMIT=$(git merge-base ${{ github.event.pull_request.base.sha }} HEAD)
echo "Base commit (merge-base): $BASE_COMMIT"
CHANGED_FILES=$(git diff --name-only "$BASE_COMMIT" HEAD)

else
echo "Warning: No PR base SHA available, skipping file check"
echo "should_skip=${SHOULD_SKIP}" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -177,9 +194,36 @@ runs:
done <<< "$CHANGED_FILES"

if [ "$ALL_FILES_MATCH_PATTERN" = "true" ]; then
SHOULD_SKIP="true"
SKIP_REASON="All changed files match skip patterns: $FILE_PATTERNS"
echo "✓ All changed files match skip patterns - build will be skipped"
echo "✓ All changed files match skip patterns"

# First-build protection: when pr-number is set, only skip if a PR
# image already exists. This ensures the first build always runs so
# that e2e tests have an image to test against.
PR_NUMBER="${{ inputs.pr-number }}"
if [ -n "$PR_NUMBER" ]; then
echo ""
echo "::group::First-build protection — checking for existing PR image"
PR_IMAGE_TAG="docker://${{ inputs.registry }}/${{ inputs.image }}:pr-${PR_NUMBER}"
echo "Checking for PR image: ${PR_IMAGE_TAG}"

skopeo inspect "${PR_IMAGE_TAG}" &>/dev/null
PR_IMAGE_EXISTS=$?

if [ $PR_IMAGE_EXISTS -eq 0 ]; then
SHOULD_SKIP="true"
SKIP_REASON="All changed files match skip patterns and PR image pr-${PR_NUMBER} already exists"
echo "PR image exists - safe to skip build"
else
SHOULD_SKIP="false"
SKIP_REASON="All changed files match skip patterns but no PR image exists yet — first build needed for e2e tests"
echo "No PR image found - first build required"
fi
echo "::endgroup::"
else
SHOULD_SKIP="true"
SKIP_REASON="All changed files match skip patterns: $FILE_PATTERNS"
echo "Build will be skipped"
fi
else
echo "✗ Found ${#NON_MATCHING_FILES[@]} file(s) not matching skip patterns:"
printf ' - %s\n' "${NON_MATCHING_FILES[@]}"
Expand Down
Loading