Skip to content

Commit 8829b56

Browse files
committed
Merge remote-tracking branch 'origin/main' into chore/workflow-rework
2 parents 3e1e761 + 188e061 commit 8829b56

21 files changed

Lines changed: 790 additions & 104 deletions

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
# CHANGELOG
22

33

4+
## v0.54.6 (2026-07-17)
5+
6+
### Bug Fixes
7+
8+
- **report**: Let template copy failures propagate
9+
([#496](https://github.com/posit-dev/vip/pull/496),
10+
[`7acf18d`](https://github.com/posit-dev/vip/commit/7acf18d4ccdd5b1bee0dd0183598077916c61d7c))
11+
12+
### Documentation
13+
14+
- **website**: Refresh getting started and feature matrix content
15+
([#488](https://github.com/posit-dev/vip/pull/488),
16+
[`a0eef4f`](https://github.com/posit-dev/vip/commit/a0eef4fefd1720793682c2cf192c212d6345b121))
17+
18+
19+
## v0.54.5 (2026-07-17)
20+
21+
### Bug Fixes
22+
23+
- **report**: Render from any directory and add badge styling
24+
([#487](https://github.com/posit-dev/vip/pull/487),
25+
[`d038eb9`](https://github.com/posit-dev/vip/commit/d038eb95bf85d3bbb773604aa134c7fe26f41ee3))
26+
27+
28+
## v0.54.4 (2026-07-17)
29+
30+
### Bug Fixes
31+
32+
- **workbench**: Make JupyterLab launch/exec resilient to SPA timing
33+
([#494](https://github.com/posit-dev/vip/pull/494),
34+
[`31f2728`](https://github.com/posit-dev/vip/commit/31f27285e733a1e2739d80a4777ffa75b12fea42))
35+
36+
437
## v0.54.3 (2026-07-17)
538

639
### Bug Fixes

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@
77
An open-source, extensible test suite that validates Posit Team deployments are
88
installed correctly and functioning properly.
99

10-
VIP uses **BDD-style tests** (pytest-bdd + Playwright) to verify Connect,
11-
Workbench, and Package Manager across standalone, Kubernetes, and Snowflake
12-
Native App deployments. Results are compiled into an **HTML report** that can
13-
be published to a Connect server.
10+
VIP uses BDD-style tests (pytest-bdd + Playwright) to verify Connect,
11+
Workbench, and Package Manager deployments. Results can be viewed
12+
from the command-line output or compiled into an HTML report.
1413

1514
**Documentation:** https://posit-dev.github.io/vip/
1615

1716
## Quick start
1817

1918
```bash
20-
uv venv
21-
source .venv/bin/activate
22-
uv pip install posit-vip
23-
uv run vip install
19+
uv tool install posit-vip
20+
vip install
2421
vip verify --connect-url https://connect.example.com --interactive-auth
2522
```
2623

@@ -48,9 +45,11 @@ vip verify --config vip.toml
4845
To reverse what `vip install` (or `just setup`) did:
4946

5047
```bash
51-
uv run vip uninstall # dry run; prints the full plan including any sudo command
52-
uv run vip uninstall --yes # remove Playwright cache + manifest; prints the sudo command
53-
# for any system packages so you can remove them yourself
48+
vip uninstall # dry run; prints the full plan including any sudo command
49+
vip uninstall --yes # remove Playwright cache + manifest; prints the sudo command
50+
# for any system packages so you can remove them yourself
51+
52+
uv tool uninstall posit-vip # remove vip itself once you're done
5453
```
5554

5655
`vip uninstall` only removes packages and files that `vip install` recorded

pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "posit-vip"
3-
version = "0.54.3"
3+
version = "0.54.6"
44
description = "Verified Installation of Posit - An extensible test suite for validating Posit Team deployments"
55
readme = "README.md"
66
license = { file = "LICENSE" }
@@ -148,6 +148,13 @@ packages = ["src/vip", "src/vip_tests"]
148148

149149
[tool.hatch.build.targets.wheel.force-include]
150150
"examples/cross_product_validation" = "vip/_scaffold/cross_product_validation"
151+
# Quarto report templates so `vip report` works when installed as a wheel,
152+
# not only from a source checkout. Copied into the working ./report dir by
153+
# run_report(). Keep this list in sync with cli._REPORT_TEMPLATE_FILES.
154+
"report/index.qmd" = "vip/_report/index.qmd"
155+
"report/details.qmd" = "vip/_report/details.qmd"
156+
"report/_quarto.yml" = "vip/_report/_quarto.yml"
157+
"report/styles.css" = "vip/_report/styles.css"
151158

152159
[tool.pytest.ini_options]
153160
testpaths = ["src/vip_tests"]

report/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/.quarto/
2+
**/*.quarto_ipynb

report/_quarto.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ format:
1616
theme: cosmo
1717
toc: true
1818
code-fold: true
19+
css: styles.css

report/details.qmd

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,29 @@ from pathlib import Path
1717
from IPython.display import HTML, Markdown, display
1818
1919
from vip.gherkin import parse_feature_file
20-
from vip.reporting import load_results, load_troubleshooting
20+
from vip.reporting import (
21+
feature_file_for_nodeid,
22+
load_results,
23+
load_troubleshooting,
24+
troubleshooting_path,
25+
)
2126
2227
data = load_results(Path("results.json"))
23-
hints = load_troubleshooting(Path("../src/vip_tests/troubleshooting.toml"))
28+
_tp = troubleshooting_path()
29+
hints = load_troubleshooting(_tp) if _tp else {}
2430
2531
_feature_cache: dict[str, dict] = {}
2632
2733
2834
def _get_feature(nodeid: str) -> dict | None:
29-
py_file = nodeid.split("::")[0] if "::" in nodeid else nodeid
30-
feature_file = py_file.rsplit(".", 1)[0] + ".feature"
31-
if feature_file not in _feature_cache:
32-
p = Path("..") / feature_file
33-
if p.exists():
34-
_feature_cache[feature_file] = parse_feature_file(p)
35+
feature_file = feature_file_for_nodeid(nodeid)
36+
key = str(feature_file) if feature_file else nodeid
37+
if key not in _feature_cache:
38+
if feature_file is not None:
39+
_feature_cache[key] = parse_feature_file(feature_file)
3540
else:
36-
_feature_cache[feature_file] = {}
37-
return _feature_cache[feature_file] or None
41+
_feature_cache[key] = {}
42+
return _feature_cache[key] or None
3843
3944
4045
def _get_steps(item) -> list[str]:

report/index.qmd

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,27 @@ from html import escape as _esc
7474
from IPython.display import HTML
7575
7676
from vip.gherkin import parse_feature_file
77-
from vip.reporting import load_troubleshooting
78-
79-
_hints = load_troubleshooting(Path("../src/vip_tests/troubleshooting.toml"))
77+
from vip.reporting import (
78+
feature_file_for_nodeid,
79+
load_troubleshooting,
80+
troubleshooting_path,
81+
)
82+
83+
_tp = troubleshooting_path()
84+
_hints = load_troubleshooting(_tp) if _tp else {}
8085
_feature_cache: dict[str, dict] = {}
8186
_error_idx = 0
8287
8388
8489
def _get_feature(nodeid: str) -> dict | None:
85-
py_file = nodeid.split("::")[0] if "::" in nodeid else nodeid
86-
feature_file = py_file.rsplit(".", 1)[0] + ".feature"
87-
if feature_file not in _feature_cache:
88-
p = Path("..") / feature_file
89-
if p.exists():
90-
_feature_cache[feature_file] = parse_feature_file(p)
90+
feature_file = feature_file_for_nodeid(nodeid)
91+
key = str(feature_file) if feature_file else nodeid
92+
if key not in _feature_cache:
93+
if feature_file is not None:
94+
_feature_cache[key] = parse_feature_file(feature_file)
9195
else:
92-
_feature_cache[feature_file] = {}
93-
return _feature_cache[feature_file] or None
96+
_feature_cache[key] = {}
97+
return _feature_cache[key] or None
9498
9599
96100
def _get_steps(item) -> list[str]:

report/styles.css

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Shared styles for the VIP Quarto report.
2+
Product/category badges rendered by index.qmd and details.qmd reference the
3+
.badge-* classes below (see _PRODUCT_BADGE_CSS in those files). Keeping them
4+
here — loaded via _quarto.yml's format.html.css — means both pages share one
5+
definition instead of duplicating it in each inline <style> block. */
6+
7+
/* Product badges */
8+
.badge-connect,
9+
.badge-workbench,
10+
.badge-package-manager,
11+
.badge-security,
12+
.badge-prerequisites {
13+
display: inline-block;
14+
color: white;
15+
padding: 2px 8px;
16+
border-radius: 12px;
17+
font-size: 0.75em;
18+
font-weight: 600;
19+
margin-left: 6px;
20+
}
21+
22+
.badge-connect {
23+
background-color: #447099;
24+
}
25+
26+
.badge-workbench {
27+
background-color: #72994e;
28+
}
29+
30+
.badge-package-manager {
31+
background-color: #9a4665;
32+
}
33+
34+
.badge-security {
35+
background-color: #d4526e;
36+
}
37+
38+
.badge-prerequisites {
39+
background-color: #6c757d;
40+
}

scripts/generate-feature-matrix.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,12 @@ def generate_matrix(tests_dir: Path, output: Path) -> dict:
232232

233233
# Not-yet-covered areas (from issue #108).
234234
not_covered = [
235-
{"name": "Flightdeck", "description": "Not yet available in VIP"},
236235
{
237236
"name": "LDAP/SAML/OAuth2 auth flows in CI",
238237
"description": "Requires identity provider setup",
239238
},
240239
{"name": "Connect scheduled content", "description": "Planned for future release"},
241240
{"name": "Workbench HA/multi-node", "description": "Planned for future release"},
242-
{"name": "Package Manager admin UI", "description": "Planned for future release"},
243241
]
244242

245243
matrix = {

0 commit comments

Comments
 (0)