-
-
Notifications
You must be signed in to change notification settings - Fork 372
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce package for Briefcase Automation
- Loading branch information
Showing
12 changed files
with
296 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
## Briefcase Automation | ||
|
||
This package provides Briefcase plugins to facilitate automation in CI. | ||
|
||
This package is internal to Briefcase's own development and is not needed to create, | ||
develop, or distribute apps created with Briefcase. | ||
|
||
### Bootstraps | ||
|
||
There are bootstrap plugins for each GUI toolkit; each allows for Briefcase to create | ||
a project using the toolkit but when the project's app run, the app automatically exits | ||
after a few seconds. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
[build-system] | ||
requires = [ | ||
# keep versions in sync with ../pyproject.toml | ||
"setuptools==69.0.0", | ||
"setuptools_scm==8.0.4", | ||
"setuptools_dynamic_dependencies @ git+https://github.com/beeware/setuptools_dynamic_dependencies", | ||
] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[project] | ||
name = "x-briefcase-automation" | ||
description = "A Briefcase plugin for CI automation." | ||
readme = "README.md" | ||
license.text = "New BSD" | ||
classifiers = ["Private :: Do Not Upload"] | ||
dynamic = ["version", "dependencies"] | ||
|
||
[project.entry-points."briefcase.bootstraps"] | ||
"Toga Automation" = "automation.bootstraps.toga:TogaAutomationBootstrap" | ||
"PySide6 Automation" = "automation.bootstraps.pyside6:PySide6AutomationBootstrap" | ||
"Pygame Automation" = "automation.bootstraps.pygame:PygameAutomationBootstrap" | ||
"PursuedPyBear Automation" = "automation.bootstraps.pursuedpybear:PursuedPyBearAutomationBootstrap" | ||
|
||
[tool.setuptools_scm] | ||
root = "../" | ||
|
||
[tool.setuptools_dynamic_dependencies] | ||
dependencies = ["briefcase == {version}"] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
BRIEFCASE_EXIT_SUCCESS_SIGNAL = ">>>>>>>>>> EXIT 0 <<<<<<<<<<" | ||
EXIT_SUCCESS_NOTIFY = ">>> successfully started...exiting <<<" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import sys | ||
|
||
import tomli_w | ||
|
||
if sys.version_info >= (3, 11): | ||
import tomllib | ||
else: | ||
import tomli as tomllib | ||
|
||
from automation.bootstraps import BRIEFCASE_EXIT_SUCCESS_SIGNAL, EXIT_SUCCESS_NOTIFY | ||
from briefcase.bootstraps import PursuedPyBearGuiBootstrap | ||
|
||
|
||
class PursuedPyBearAutomationBootstrap(PursuedPyBearGuiBootstrap): | ||
def app_source(self): | ||
return f"""\ | ||
import importlib.metadata | ||
import os | ||
import sys | ||
import ppb | ||
class {{{{ cookiecutter.class_name }}}}(ppb.Scene): | ||
def __init__(self, **props): | ||
super().__init__(**props) | ||
self.updates: int = 0 | ||
self.add( | ||
ppb.Sprite( | ||
image=ppb.Image("{{{{ cookiecutter.module_name }}}}/resources/{{{{ cookiecutter.app_name }}}}.png"), | ||
) | ||
) | ||
def on_update(self, event, signal): | ||
self.updates += 1 | ||
# quit after 2 seconds since on_update is run 60 times/second | ||
if self.updates > 120: | ||
print("{EXIT_SUCCESS_NOTIFY}") | ||
print("{BRIEFCASE_EXIT_SUCCESS_SIGNAL}") | ||
signal(ppb.events.Quit()) | ||
def main(): | ||
# Linux desktop environments use an app's .desktop file to integrate the app | ||
# in to their application menus. The .desktop file of this app will include | ||
# the StartupWMClass key, set to app's formal name. This helps associate the | ||
# app's windows to its menu item. | ||
# | ||
# For association to work, any windows of the app must have WMCLASS property | ||
# set to match the value set in app's desktop file. For PPB, this is set | ||
# using the SDL_VIDEO_X11_WMCLASS environment variable. | ||
# Find the name of the module that was used to start the app | ||
app_module = sys.modules["__main__"].__package__ | ||
# Retrieve the app's metadata | ||
metadata = importlib.metadata.metadata(app_module) | ||
os.environ["SDL_VIDEO_X11_WMCLASS"] = metadata["Formal-Name"] | ||
ppb.run( | ||
starting_scene={{{{ cookiecutter.class_name }}}}, | ||
title=metadata["Formal-Name"], | ||
) | ||
""" | ||
|
||
# The constraint of pysdl2-dll==2.0.22 is required for ppb==1.1.0; | ||
# the libraries in later versions of pysdl2-dll are not compatible. | ||
|
||
def pyproject_table_linux_flatpak(self): | ||
table = tomllib.loads(super().pyproject_table_linux_flatpak()) | ||
table.setdefault("requires", []).append("pysdl2-dll==2.0.22") | ||
return f"\n{tomli_w.dumps(table)}" | ||
|
||
def pyproject_table_windows(self): | ||
table = tomllib.loads(super().pyproject_table_windows()) | ||
table.setdefault("requires", []).append("pysdl2-dll==2.0.22") | ||
return f"\n{tomli_w.dumps(table)}" | ||
|
||
def pyproject_table_macOS(self): | ||
table = tomllib.loads(super().pyproject_table_macOS()) | ||
table.setdefault("requires", []).append("pysdl2-dll==2.0.22") | ||
return f"\n{tomli_w.dumps(table)}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from automation.bootstraps import BRIEFCASE_EXIT_SUCCESS_SIGNAL, EXIT_SUCCESS_NOTIFY | ||
from briefcase.bootstraps import PygameGuiBootstrap | ||
|
||
|
||
class PygameAutomationBootstrap(PygameGuiBootstrap): | ||
def app_source(self): | ||
return f"""\ | ||
import importlib.metadata | ||
import os | ||
import sys | ||
from pathlib import Path | ||
import pygame | ||
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600 | ||
WHITE = (255, 255, 255) | ||
def main(): | ||
# Linux desktop environments use an app's .desktop file to integrate the app | ||
# in to their application menus. The .desktop file of this app will include | ||
# the StartupWMClass key, set to app's formal name. This helps associate the | ||
# app's windows to its menu item. | ||
# | ||
# For association to work, any windows of the app must have WMCLASS property | ||
# set to match the value set in app's desktop file. For PyGame, this is set | ||
# using the SDL_VIDEO_X11_WMCLASS environment variable. | ||
# Find the name of the module that was used to start the app | ||
app_module = sys.modules["__main__"].__package__ | ||
# Retrieve the app's metadata | ||
metadata = importlib.metadata.metadata(app_module) | ||
os.environ["SDL_VIDEO_X11_WMCLASS"] = metadata["Formal-Name"] | ||
# Set the app's runtime icon | ||
pygame.display.set_icon( | ||
pygame.image.load(Path(__file__).parent / "resources/{{{{ cookiecutter.app_name }}}}.png") | ||
) | ||
pygame.init() | ||
pygame.display.set_caption(metadata["Formal-Name"]) | ||
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) | ||
pygame.time.set_timer(pygame.QUIT, 2000) | ||
running = True | ||
while running: | ||
for event in pygame.event.get(): | ||
if event.type == pygame.QUIT: | ||
print("{EXIT_SUCCESS_NOTIFY}") | ||
print("{BRIEFCASE_EXIT_SUCCESS_SIGNAL}") | ||
running = False | ||
break | ||
screen.fill(WHITE) | ||
pygame.display.flip() | ||
pygame.quit() | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from automation.bootstraps import BRIEFCASE_EXIT_SUCCESS_SIGNAL, EXIT_SUCCESS_NOTIFY | ||
from briefcase.bootstraps import PySide6GuiBootstrap | ||
|
||
|
||
class PySide6AutomationBootstrap(PySide6GuiBootstrap): | ||
def app_source(self): | ||
return f"""\ | ||
import importlib.metadata | ||
import sys | ||
from PySide6 import QtWidgets | ||
from PySide6.QtCore import QTimer | ||
class {{{{ cookiecutter.class_name }}}}(QtWidgets.QMainWindow): | ||
def __init__(self): | ||
super().__init__() | ||
self.init_ui() | ||
def init_ui(self): | ||
self.setWindowTitle("{{{{ cookiecutter.app_name }}}}") | ||
self.show() | ||
QTimer.singleShot(2000, self.exit_app) | ||
def exit_app(self): | ||
print("{EXIT_SUCCESS_NOTIFY}") | ||
print("{BRIEFCASE_EXIT_SUCCESS_SIGNAL}") | ||
QtWidgets.QApplication.quit() | ||
def main(): | ||
# Linux desktop environments use an app's .desktop file to integrate the app | ||
# in to their application menus. The .desktop file of this app will include | ||
# the StartupWMClass key, set to app's formal name. This helps associate the | ||
# app's windows to its menu item. | ||
# | ||
# For association to work, any windows of the app must have WMCLASS property | ||
# set to match the value set in app's desktop file. For PySide6, this is set | ||
# with setApplicationName(). | ||
# Find the name of the module that was used to start the app | ||
app_module = sys.modules["__main__"].__package__ | ||
# Retrieve the app's metadata | ||
metadata = importlib.metadata.metadata(app_module) | ||
QtWidgets.QApplication.setApplicationName(metadata["Formal-Name"]) | ||
app = QtWidgets.QApplication(sys.argv) | ||
main_window = {{{{ cookiecutter.class_name }}}}() | ||
sys.exit(app.exec()) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from automation.bootstraps import BRIEFCASE_EXIT_SUCCESS_SIGNAL, EXIT_SUCCESS_NOTIFY | ||
from briefcase.bootstraps import TogaGuiBootstrap | ||
|
||
|
||
class TogaAutomationBootstrap(TogaGuiBootstrap): | ||
def app_source(self): | ||
return f'''\ | ||
import asyncio | ||
import toga | ||
from toga.style import Pack | ||
from toga.style.pack import COLUMN, ROW | ||
class {{{{ cookiecutter.class_name }}}}(toga.App): | ||
def startup(self): | ||
"""Construct and show the Toga application. | ||
Usually, you would add your application to a main content box. | ||
We then create a main window (with a name matching the app), and | ||
show the main window. | ||
""" | ||
main_box = toga.Box() | ||
self.main_window = toga.MainWindow(title=self.formal_name) | ||
self.main_window.content = main_box | ||
self.main_window.show() | ||
self.add_background_task(self.exit_soon) | ||
async def exit_soon(self, app: toga.App, **kwargs): | ||
"""Background task that closes the app after a few seconds.""" | ||
await asyncio.sleep(2) | ||
print("{EXIT_SUCCESS_NOTIFY}") | ||
print("{BRIEFCASE_EXIT_SUCCESS_SIGNAL}") | ||
self.exit() | ||
def main(): | ||
return {{{{ cookiecutter.class_name }}}}() | ||
''' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The Briefcase Automation package was created to facilitate automated testing in CI; for example, starting apps built in CI that can automatically exit. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters