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
37 changes: 37 additions & 0 deletions .github/workflows/ci-cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI/CD Pipeline

on:
push:
branches:
- '**'
tags:
- 'v*.*.*'
pull_request:
branches:
- '**'
workflow_dispatch:

jobs:
lint:
uses: ./.github/workflows/ruff.yaml

test:
needs: lint
uses: ./.github/workflows/pytest.yaml

docker:
needs: test
uses: ./.github/workflows/docker-build-and-scan.yaml
with:
DOCKER_PATH_CONTEXT: .
DOCKER_BUILD_DOCKERFILE: ./Dockerfile
DOCKER_TAGS: ${{ github.repository }}:${{ github.sha }}
DOCKER_LOAD_BOOL: false
DOCKER_PUSH_BOOL: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }}
secrets: inherit

release:
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
needs: [test, docker]
uses: ./.github/workflows/release.yaml
secrets: inherit
10 changes: 4 additions & 6 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
name: Unit Test & Coverage
name: Unit Test & Coverage (Reusable)

on:
pull_request:
branches:
- '*'
workflow_call:

jobs:
unit-test-coverage:
runs-on: ubuntu-latest
permissions:
contents: read
env:
UV_VERSION: '0.10.2'
UV_VERSION: '>=0.10.2'
PYTHON_VERSION: '3.13'
steps:
- name: Checkout repository
Expand Down Expand Up @@ -45,7 +43,7 @@ jobs:
uv run -- coverage report --show-missing

- name: Save uv caches
if: steps.cache-restore.outputs.cache-hit != 'true'
if: always()
uses: actions/cache/save@v5
with:
path: |
Expand Down
22 changes: 5 additions & 17 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
name: UV - Release

name: UV - Release (Reusable)
on:
push:
branches:
- main

workflow_call:
jobs:
Semantic-Release:
runs-on: ubuntu-latest
Expand All @@ -19,7 +15,7 @@ jobs:
dist_artifacts_name: dist
dist_artifacts_dir: dist
lock_file_artifact: uv.lock
UV_VERSION: '0.10.2'
UV_VERSION: '>=0.10.2'
PYTHON_VERSION: '3.13'
GITHUB_ACTIONS_AUTHOR_NAME: github-actions
GITHUB_ACTIONS_AUTHOR_EMAIL: actions@users.noreply.github.com
Expand All @@ -28,11 +24,9 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}

- name: Setup | Force release branch to be at workflow sha
run: |
git reset --hard ${{ github.sha }}

- name: Restore global uv cache
id: cache-restore
uses: actions/cache/restore@v5
Expand All @@ -44,31 +38,25 @@ jobs:
key: uv-main-${{ env.UV_VERSION }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('pyproject.toml', 'uv.lock') }}
restore-keys: |
uv-main-

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: ${{ env.UV_VERSION }}
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: false

- name: Action | Semantic Version Release
id: release
uses: python-semantic-release/python-semantic-release@v10.5.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
git_committer_name: 'github-actions'
git_committer_email: 'actions@users.noreply.github.com'

- name: Publish | Upload to GitHub Release Assets
- name: Action | Create GitHub Release
uses: python-semantic-release/publish-action@v10.5.3
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.release.outputs.tag }}

- name: Save uv caches
if: steps.cache-restore.outputs.cache-hit != 'true'
if: always()
uses: actions/cache/save@v5
with:
path: |
Expand Down
10 changes: 4 additions & 6 deletions .github/workflows/ruff.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
name: UV Build - Ruff Lint
name: Ruff Lint (Reusable)

on:
pull_request:
branches:
- '*'
workflow_call:

jobs:
ruff-lint:
runs-on: ubuntu-latest
permissions:
contents: read
env:
UV_VERSION: '0.10.2'
UV_VERSION: '>=0.10.2'
PYTHON_VERSION: '3.13'

steps:
Expand Down Expand Up @@ -46,7 +44,7 @@ jobs:
uv run ruff check tests

- name: Save uv caches
if: steps.cache-restore.outputs.cache-hit != 'true'
if: always()
uses: actions/cache/save@v5
with:
path: |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependencies = [
build = ["uv >= 0.10.2"]

[build-system]
requires = ["uv_build >= 0.10.2, < 0.11.0"]
requires = ["uv_build >= 0.10.2"]
build-backend = "uv_build"

[project.scripts]
Expand Down
111 changes: 104 additions & 7 deletions src/sample_python_app/core/display.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
"""Handles formatting and displaying astronomical data using rich and pyfiglet."""

from datetime import datetime

from pyfiglet import Figlet
from rich.align import Align
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from sample_python_app.core.config import settings
from sample_python_app.core.logging import setup_logger
Expand All @@ -19,16 +25,107 @@ def display_astronomical_data(astro):
"""
logger = setup_logger(mode="silent")
console = Console()
header = Figlet(font="small", width=100).renderText("Astronomical Data")
logger.info("Displaying Astronomical Data header.")
console.print(f"[bold magenta]{header}[/bold magenta]")
# Synthwave color palette (no longer used)

header = Figlet(font="slant", width=120).renderText("SYNTHWAVE SUNRISE 🌅")
logger.info("Displaying Synthwave Sunrise header.")
header_text = Text(header)
header_text.stylize("bold magenta")

sunrise_local = astro.sunrise.astimezone(settings.tz)
sunset_local = astro.sunset.astimezone(settings.tz)
date_art = Figlet(font="mini", width=150).renderText(
sunrise_local.strftime("%A, %B %d, %Y")
)
logger.info(f'Displaying date: {sunrise_local.strftime("%A, %B %d, %Y")}')
console.print(f"[bold cyan]{date_art}[/bold cyan]")
for name, value in astro.formatted(settings.tz, settings.DATE_FORMAT).items():
logger.info(f'Displaying date: {sunrise_local.strftime("%A, %B %d, %Y")})')
date_text = Text(date_art)
date_text.stylize("bold cyan")

# Stylized sunrise/sunset
sun_art = Figlet(font="starwars", width=120).renderText("SUNRISE")
sun_set_art = Figlet(font="starwars", width=120).renderText("SUNSET")
sun_text = Text(sun_art)
sun_text.stylize("bold yellow")
# Sunrise time as figlet
sunrise_time_art = Figlet(font="big", width=100).renderText(
sunrise_local.strftime("%H:%M:%S")
)
sunrise_time_text = Text(sunrise_time_art)
sunrise_time_text.stylize("bold yellow")

sun_set_text = Text(sun_set_art)
sun_set_text.stylize("bold blue")
# Sunrise time as figlet with AM/PM
sunrise_time_str = sunrise_local.strftime("%I:%M:%S %p")
sunrise_time_art = Figlet(font="big", width=100).renderText(sunrise_time_str)
sunrise_time_text = Text(sunrise_time_art)
sunrise_time_text.stylize("bold yellow")

sun_set_text = Text(sun_set_art)
sun_set_text.stylize("bold blue")
# Sunset time as figlet with AM/PM
sunset_time_str = sunset_local.strftime("%I:%M:%S %p")
sunset_time_art = Figlet(font="big", width=100).renderText(sunset_time_str)
sunset_time_text = Text(sunset_time_art)
sunset_time_text.stylize("bold blue")
from rich.table import Table

astro_table = Table(show_header=True, header_style="bold magenta", box=None)
astro_table.add_column("Event", style="bold #ff00cc")
astro_table.add_column("Local Time", style="bold #00eaff")
tz = settings.tz
time_fmt = "%I:%M:%S %p %Z"
# Color mapping for event types
event_colors = {
"sunrise": "#ffe066", # yellow
"sunset": "#5dade2", # blue
"transit": "#ffb347", # orange
"civil twilight begin": "#f7cac9", # pink
"civil twilight end": "#92a8d1", # light blue
"nautical twilight begin": "#f9d423", # gold
"nautical twilight end": "#6a89cc", # purple-blue
"astronomical twilight begin": "#b388ff", # violet
"astronomical twilight end": "#2e86c1", # deep blue
}
for name, dt in astro.as_local(tz).items():
label = name.replace("_", " ").title()
if isinstance(dt, datetime):
value = dt.strftime(time_fmt)
else:
value = str(dt)
logger.info(f"Displaying {label}: {value}")
console.print(f"[bold cyan]{label}: [white]{value}[/white]")
# Pick color based on event type
color = event_colors.get(label.lower(), "#e17055") # fallback: coral
astro_table.add_row(
f"[{color}]{label}[/{color}]", f"[{color}]{value}[/{color}]"
)

# Compose all parts into a single renderable for the panel
from rich.console import Group

from rich.columns import Columns

# Combine sunrise and sunset figlet art and times in the same row
sun_figlet_row = Columns(
[
Group(Align.center(sun_text), Align.center(sunrise_time_text)),
Group(Align.center(sun_set_text), Align.center(sunset_time_text)),
],
align="center",
expand=True,
)

panel_content = Group(
Align.center(header_text),
Align.center(date_text),
sun_figlet_row,
Align.center(astro_table),
)
console.print(
Panel(
panel_content,
title="[bold #ff6ec7]Synthwave Astronomical Events[/bold #ff6ec7]",
border_style="#ff00cc",
padding=(1, 2),
)
)
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.