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

[CI] Enable PyCafe dashboards in CI #816

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
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
47 changes: 47 additions & 0 deletions .github/workflows/pycafe-dashboards-in-CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: PyCafe Dashboards in CI

on:
push:
branches: [main]
pull_request:
branches:
- main

env:
PYTHON_VERSION: "3.12"

jobs:
create-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tools/tools_requirements.txt
pip install hatch
- name: "Build vizro-core package"
run: |
cd vizro-core
hatch build
- name: "Upload artifact"
uses: actions/upload-artifact@v4
with:
name: pip
path: vizro-core/dist/*.whl
retention-days: 14

- name: "Create PyCafe links"
env:
GITHUB_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.run_id }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.number }}

run: |
cd vizro-core
hatch run python ../tools/pycafe/create_pycafe_links.py examples/scratch_dev/ examples/dev/ examples/visual-vocabulary/
131 changes: 131 additions & 0 deletions tools/pycafe/create_pycafe_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""Generate PyCafe links for the example dashboards and post them as a comment on the pull request and as status."""

import base64
import datetime
import gzip
import json
import os
import subprocess
import sys
import textwrap
from pathlib import Path
from typing import Optional
from urllib.parse import quote, urlencode

from github import Auth, Github

GITHUB_TOKEN = str(os.getenv("GITHUB_TOKEN"))
REPO_NAME = str(os.getenv("GITHUB_REPOSITORY"))
PR_NUMBER = int(os.getenv("PR_NUMBER"))
RUN_ID = str(os.getenv("RUN_ID"))
PACKAGE_VERSION = subprocess.check_output(["hatch", "version"]).decode("utf-8").strip()
PYCAFE_URL = "https://py.cafe"

# Access
auth = Auth.Token(GITHUB_TOKEN)
g = Github(auth=auth)

# Get PR and commits
repo = g.get_repo(REPO_NAME)
pr = repo.get_pull(PR_NUMBER)
commit_sha = pr.head.sha
commit = repo.get_commit(commit_sha)


def generate_link(directory: str, extra_requirements: Optional[list[str]] = None):
"""Generate a PyCafe link for the example dashboards."""
base_url = f"https://raw.githubusercontent.com/mckinsey/vizro/{commit_sha}/vizro-core/{directory}"

# Requirements
extra_requirements_concat = "\n".join(extra_requirements) if extra_requirements else ""
requirements = (
f"""{PYCAFE_URL}/gh/artifact/mckinsey/vizro/actions/runs/{RUN_ID}/pip/vizro-{PACKAGE_VERSION}-py3-none-any.whl\n"""
+ extra_requirements_concat
)

# App file
app_file_path = os.path.join(directory, "app.py")
app_content = Path(app_file_path).read_text()
app_content_split = app_content.split('if __name__ == "__main__":')
if len(app_content_split) > 1:
app_content = app_content_split[0] + textwrap.dedent(app_content_split[1])

# JSON object
json_object = {
"code": str(app_content),
"requirements": requirements,
"files": [],
}
for root, _, files in os.walk("./" + directory):
for file in files:
if "app.py" in file:
continue
file_path = os.path.join(root, file)
relative_path = os.path.relpath(file_path, directory)
file_url = f"{base_url}{relative_path.replace(os.sep, '/')}"
json_object["files"].append({"name": relative_path, "url": file_url})

json_text = json.dumps(json_object)
compressed_json_text = gzip.compress(json_text.encode("utf8"))
base64_text = base64.b64encode(compressed_json_text).decode("utf8")
query = urlencode({"c": base64_text}, quote_via=quote)
return f"{PYCAFE_URL}/snippet/vizro/v1?{query}"


def post_comment(urls: list[tuple[str, str]]):
"""Post a comment on the pull request with the links to the PyCafe dashboards."""
# Inspired by https://github.com/snehilvj/dash-mantine-components

# Find existing comments by the bot
comments = pr.get_issue_comments()
bot_comment = None
for comment in comments:
if comment.body.startswith("View the example dashboards of the current commit live"):
bot_comment = comment
break

# Get current UTC datetime
current_utc_time = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d %H:%M:%S UTC")

# Define the comment body with datetime
dashboards = "\n\n".join(f"Link: [{directory}]({url})" for url, directory in urls)

comment_body = f"""View the example dashboards of the current commit live on PyCafe:\n
Updated on: {current_utc_time}
Commit: {commit_sha}

{dashboards}
"""

# Update the existing comment or create a new one
if bot_comment:
bot_comment.edit(comment_body)
print("Comment updated on the pull request.") # noqa
else:
pr.create_issue_comment(comment_body)
print("Comment added to the pull request.") # noqa


if __name__ == "__main__":
urls = []

# Generate links for each directory and create status
for directory in sys.argv[1:]:
# Add any extra requirements for specific dev examples
if directory == "examples/dev/":
url = generate_link(directory=directory, extra_requirements=["openpyxl"])
else:
url = generate_link(directory=directory)
urls.append((url, directory))

# Define the deployment status
state = "success" # Options: 'error', 'failure', 'pending', 'success'
description = "Test out the app live on PyCafe"
context = f"PyCafe Example ({directory})"

# Create the status on the commit
commit.create_status(state=state, target_url=url, description=description, context=context)
print(f"Status created for {context} with URL: {url}") # noqa

# Post the comment with the links
post_comment(urls)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!--
A new scriv changelog fragment.

Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨

- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Removed

- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Added

- A bullet item for the Added category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Changed

- A bullet item for the Changed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Deprecated

- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Fixed

- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
<!--
### Security

- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))

-->
2 changes: 1 addition & 1 deletion vizro-core/examples/scratch_dev/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@


page = vm.Page(
title="Diverging bar",
title="Test I",
components=[
vm.Graph(
figure=px.bar(
Expand Down
1 change: 0 additions & 1 deletion vizro-core/examples/scratch_dev/charts/__init__.py

This file was deleted.

54 changes: 0 additions & 54 deletions vizro-core/examples/scratch_dev/charts/charts.py

This file was deleted.

3 changes: 2 additions & 1 deletion vizro-core/hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ dependencies = [
"pyyaml",
"openpyxl",
"jupyter",
"pre-commit"
"pre-commit",
"PyGithub"
]
installer = "uv"

Expand Down
2 changes: 1 addition & 1 deletion vizro-core/src/vizro/models/_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
html,
)

import vizro
from vizro._themes._templates.template_dashboard_overrides import dashboard_overrides

try:
Expand All @@ -31,7 +32,6 @@

from dash.development.base_component import Component

import vizro
from vizro._constants import MODULE_PAGE_404, VIZRO_ASSETS_PATH
from vizro.actions._action_loop._action_loop import ActionLoop
from vizro.models import Navigation, VizroBaseModel
Expand Down
Loading