Skip to content
Merged
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
12 changes: 10 additions & 2 deletions .github/workflows/RELEASE.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install poetry python-semantic-release
# GitPython 3.1.60 removed `Actor.name_email_regex`, which
# python-semantic-release reads unconditionally while loading its
# configuration. python-semantic-release only asks for
# `gitpython~=3.0`, so an unpinned install picks the broken one and
# every release aborts before it does anything:
# ::ERROR:: type object 'Actor' has no attribute 'name_email_regex'
# Cap GitPython below that release rather than pinning
# python-semantic-release, so this picks up the upstream fix.
pip install poetry python-semantic-release "gitpython<3.1.60"

- name: Semantic Release
id: semantic-release
Expand Down Expand Up @@ -97,7 +105,7 @@ jobs:
# 3. Update UI sidebar version (full semver)
SIDEBAR="flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx"
if [ -f "$SIDEBAR" ]; then
sed -i "s/FlowyML v[0-9]*\.[0-9]*\.[0-9]*/FlowyML v${VERSION}/" "$SIDEBAR"
sed -i "s/^const VERSION = \"[0-9]*\.[0-9]*\.[0-9]*\";/const VERSION = \"${VERSION}\";/" "$SIDEBAR"
echo "✓ Updated UI sidebar → FlowyML v${VERSION}"
fi

Expand Down
8 changes: 7 additions & 1 deletion flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import {
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';

// Bumped by semantic-release via [tool.semantic_release].version_variables,
// which rewrites assignments only. The entry used to point at the version
// printed inline in the JSX below, which it cannot match, so every release
// silently left the sidebar showing the previous version.
const VERSION = "2.2.0";

const NAV_GROUPS = [
{
title: 'Workspace',
Expand Down Expand Up @@ -171,7 +177,7 @@ export function Sidebar({ collapsed, setCollapsed, isMobile = false, mobileOpen
<>
<div className="flex items-center gap-2 mb-2">
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<p className="text-xs font-semibold text-slate-600 dark:text-slate-300 whitespace-nowrap">FlowyML v2.2.0</p>
<p className="text-xs font-semibold text-slate-600 dark:text-slate-300 whitespace-nowrap">FlowyML v{VERSION}</p>
</div>
<p className="text-[10px] text-slate-400 dark:text-slate-500 whitespace-nowrap">
Made with ❤️ by <span className="font-medium text-primary-500">UnicoLab</span>
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ markers = [
version_toml = ["pyproject.toml:tool.poetry.version"]
version_variables = [
"flowyml/__init__.py:__version__",
"flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx:FlowyML v",
"flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx:VERSION",
]
branch = "main"
upload_to_pypi = false
Expand Down
29 changes: 29 additions & 0 deletions tests/test_ci_workflow_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,32 @@ def test_titles_the_project_already_uses_are_accepted(title):
def test_malformed_titles_are_still_rejected(title):
"""The check has to keep checking something."""
assert not re.match(_pr_title_pattern(), title), f"{title!r} should not pass the PR-title check"


RELEASE_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "RELEASE.yml"


@pytest.mark.skipif(not RELEASE_WORKFLOW.exists(), reason="release workflow not present")
def test_the_release_workflow_constrains_gitpython():
"""An unpinned install of the release tooling breaks the release.

GitPython 3.1.60 removed ``Actor.name_email_regex``, which
python-semantic-release reads while loading its configuration.
python-semantic-release asks only for ``gitpython~=3.0``, so pip resolves
the broken pair and ``semantic-release version`` aborts on the first step
of the release with::

::ERROR:: type object 'Actor' has no attribute 'name_email_regex'

Nothing else in the pipeline runs, so the release produces no tag, no
PyPI upload and no docs deploy.
"""
workflow = yaml.safe_load(RELEASE_WORKFLOW.read_text(encoding="utf-8"))
steps = workflow["jobs"]["SEMANTIC_RELEASE"]["steps"]
install = next(s for s in steps if s.get("name") == "Install dependencies")["run"]

assert "python-semantic-release" in install
assert "gitpython" in install.lower(), (
"The release workflow installs python-semantic-release without "
"constraining GitPython; pip will resolve a version that breaks it."
)
56 changes: 49 additions & 7 deletions tests/test_version_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,57 @@ def test_server_info_reports_the_package_version(self, client):
assert client.get("/api/execution/info").json()["version"] == flowyml.__version__


SIDEBAR = REPO_ROOT / "flowyml" / "ui" / "frontend" / "src" / "components" / "sidebar" / "Sidebar.jsx"


def test_the_frontend_sidebar_shows_the_current_version(declared_version):
"""The sidebar literal is updated by semantic-release; verify it kept up."""
sidebar = REPO_ROOT / "flowyml" / "ui" / "frontend" / "src" / "components" / "sidebar"
sidebar_file = sidebar / "Sidebar.jsx"
if not sidebar_file.exists():
"""The sidebar constant is bumped by semantic-release; verify it kept up."""
if not SIDEBAR.exists():
pytest.skip("frontend sources not present")

text = sidebar_file.read_text(encoding="utf-8")
versions = re.findall(r"FlowyML v(\d+\.\d+\.\d+)", text)
versions = re.findall(r'^const VERSION = "(\d+\.\d+\.\d+)";', SIDEBAR.read_text(encoding="utf-8"), re.M)

assert versions, "no 'FlowyML v<version>' string found in the sidebar"
assert versions, 'no `const VERSION = "x.y.z";` found in the sidebar'
assert all(v == declared_version for v in versions), f"sidebar shows {versions}, expected {declared_version}"


def test_the_sidebar_does_not_print_a_version_inline():
"""An inline literal is invisible to the release automation.

``version_variables`` rewrites assignments; it cannot touch a number
sitting in JSX text. While the version was written straight into the
markup, every release bumped ``pyproject.toml`` and ``__init__.py`` and
left the sidebar advertising the previous version.
"""
if not SIDEBAR.exists():
pytest.skip("frontend sources not present")

inline = re.findall(r">FlowyML v\d+\.\d+\.\d+<", SIDEBAR.read_text(encoding="utf-8"))

assert not inline, f"the sidebar prints a hardcoded version in its markup: {inline}; render {{VERSION}} instead"


def test_every_release_version_variable_can_actually_be_rewritten(declared_version):
"""A ``version_variables`` entry that matches nothing fails silently.

semantic-release looks for ``<variable> = "<current version>"``. If the
entry names something that is not assigned that way it updates nothing,
reports success, and the surface keeps showing the old version - which is
exactly what happened to the sidebar.
"""
config = toml.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
entries = config["tool"]["semantic_release"]["version_variables"]

unmatched = []
for entry in entries:
path_part, _, variable = entry.rpartition(":")
target = REPO_ROOT / path_part
if not target.exists():
continue # frontend sources may be absent in a packaged checkout
pattern = rf'{re.escape(variable)}\s*[:=]\s*["\']{re.escape(declared_version)}["\']'
if not re.search(pattern, target.read_text(encoding="utf-8")):
unmatched.append(entry)

assert not unmatched, (
"these version_variables entries match nothing, so semantic-release " f"will silently skip them: {unmatched}"
)
Loading