Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a dynamic, relation-driven sidebar #118

Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cadfd27
feat: add kubeflow_dashboard_sidebar lib
ca-scribner Jun 23, 2023
aca8dd6
feat: add capture_events lib
ca-scribner Jun 23, 2023
a3c5839
refactor: move charm's k8s contex to a property
ca-scribner Jun 23, 2023
ab795b4
fix: handle multiple relations in sidebar Provider
ca-scribner Jun 23, 2023
ed3e471
fix: handle empty relations in sidebar Provider
ca-scribner Jun 23, 2023
f9a713e
feat: add Provider.get_sidebar_items_as_json
ca-scribner Jun 23, 2023
44ccb52
feat: implement sidebar Provider in charm
ca-scribner Jun 23, 2023
54992ac
fix: handle relation-broken in get_sidebar_items()
ca-scribner Jun 26, 2023
82c4543
fix: rendering of dashboard configmap
ca-scribner Jun 26, 2023
102e434
feat: add integration tests for dynamic sidebar
ca-scribner Jun 27, 2023
17b6148
fix: formatting and linting
ca-scribner Jun 27, 2023
7ac6531
fix: removed unused BASE_SIDEBAR variable
ca-scribner Jun 27, 2023
17b5cbe
fix: removed unused BASE_SIDEBAR variable from charm.py
ca-scribner Jun 27, 2023
f50a033
fix: formatting/linting
ca-scribner Jun 27, 2023
7de140c
feat: add log dumping to integration CI
ca-scribner Jun 27, 2023
e02bd9a
feat: add log dumping to integration CI
ca-scribner Jun 27, 2023
0bc7153
refactor: renamed interface to kubeflow_dashboard_sidebar
ca-scribner Jun 27, 2023
8c15742
fix: linting and linting configuration
ca-scribner Jun 27, 2023
c470658
fix: typo in dump-charm-debug-artifacts action call
ca-scribner Jun 27, 2023
1e17e01
docs: add missing docstrings, comments.
ca-scribner Jun 27, 2023
2738bb3
fix: remove outdate part of dashboard_links integration test
ca-scribner Jun 27, 2023
0afc21c
fix: formatting
ca-scribner Jun 27, 2023
5b35b9c
fix: dashboard quickLinks and Documentation links
ca-scribner Jun 28, 2023
b1f0e24
doc: add docstring in tests
ca-scribner Jun 28, 2023
887bcaf
dox: capture relation-broken handling in github issue
ca-scribner Jun 28, 2023
d4627ce
fix: re-initialise sidebar lib to v0
ca-scribner Jun 28, 2023
e880538
fix: library path in tester charm CI
ca-scribner Jun 28, 2023
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
23 changes: 4 additions & 19 deletions .github/workflows/integrate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,29 +77,14 @@ jobs:
run: |
sg microk8s -c "tox -e integration -- --model kubeflow"

- name: Get all
run: kubectl get all -A
if: failure()

- name: Get configmaps
run: kubectl get cm -A
if: failure()

- name: Get juju status
run: juju status
if: failure()

- name: Get kubeflow-profiles workload logs
run: kubectl logs --tail 100 -nkubeflow -ljuju-app=kubeflow-dashboard
if: failure()

- name: Get kubeflow-kfam workload logs
run: kubectl logs --tail 100 -nkubeflow -ljuju-app=kubeflow-dashboard
if: failure()

- name: Get operator logs
run: kubectl logs --tail 100 -nkubeflow -loperator.juju.is/name
if: failure()
- uses: canonical/kubeflow-ci/dump-charm-debug-artifacts@version
# always() if you want this to run on every run, regardless of failure.
# more details: https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions
if: always()

- name: Upload selenium screenshots
uses: actions/upload-artifact@v3
Expand Down
86 changes: 86 additions & 0 deletions lib/charms/harness_extensions/v0/capture_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'''This is a library providing a utility for unittesting events fired on a
Harness-ed Charm.

Example usage:

>>> from charms.harness_extensions.v0.capture_events import capture
>>> with capture(RelationEvent) as captured:
>>> harness.add_relation('foo', 'remote')
>>> assert captured.event.unit.name == 'remote'
'''

# The unique Charmhub library identifier, never change it
LIBID = "9fcdab70e26d4eee9797c0e542ab397a"

# Increment this major API version when introducing breaking changes
LIBAPI = 0

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 3

# Copyright 2022 Canonical Ltd.
# See LICENSE file for licensing details.

from contextlib import contextmanager
from typing import Generic, Iterator, Optional, Type, TypeVar

from ops.charm import CharmBase
from ops.framework import EventBase

_T = TypeVar("_T", bound=EventBase)


@contextmanager
def capture_events(charm: CharmBase, *types: Type[EventBase]):
"""Capture all events of type `*types` (using instance checks)."""
allowed_types = types or (EventBase,)

captured = []
_real_emit = charm.framework._emit

def _wrapped_emit(evt):
if isinstance(evt, allowed_types):
captured.append(evt)
return _real_emit(evt)

charm.framework._emit = _wrapped_emit # type: ignore # noqa # ugly

yield captured

charm.framework._emit = _real_emit # type: ignore # noqa # ugly


class Captured(Generic[_T]):
"""Object to type and expose return value of capture()."""

_event = None

@property
def event(self) -> Optional[_T]:
"""Return the captured event."""
return self._event

@event.setter
def event(self, val: _T):
self._event = val


@contextmanager
def capture(charm: CharmBase, typ_: Type[_T] = EventBase) -> Iterator[Captured[_T]]:
"""Capture exactly 1 event of type `typ_`.

Will raise if more/less events have been fired, or if the returned event
does not pass an instance check.
"""
result = Captured()
with capture_events(charm, typ_) as captured:
if not captured:
yield result

assert len(captured) <= 1, f"too many events captured: {captured}"
assert len(captured) >= 1, f"no event of type {typ_} emitted."
event = captured[0]
assert isinstance(event, typ_), f"expected {typ_}, not {type(event)}"
result.event = event

Loading