Skip to content

Add website publishing functionality for meals page#51

Merged
wassupluke merged 7 commits into
mainfrom
claude/meals-page-from-email-mtbzD
Feb 14, 2026
Merged

Add website publishing functionality for meals page#51
wassupluke merged 7 commits into
mainfrom
claude/meals-page-from-email-mtbzD

Conversation

@wassupluke
Copy link
Copy Markdown
Owner

@wassupluke wassupluke commented Feb 14, 2026

Description

This PR adds functionality to automatically publish the weekly meals page to a website repository. After generating and sending the weekly meals email, the system now wraps the email HTML content in a website template and commits/pushes it to a configured website repository.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)

Motivation and Context

The meals email content should be published to a website for broader accessibility. This change integrates website publishing into the existing recipe emailer workflow, allowing the same meal data to be distributed via both email and web.

Changes Made

Code Changes

New file: website_publisher.py

  • publish_meals_page(): Main function that wraps email HTML in website template and commits/pushes to repo
  • generate_meals_page_html(): Generates a complete HTML page from email content, including navbar template and styled meal cards
  • _git_commit_and_push(): Handles git operations (add, commit, push) with proper error handling

Modified: main.py

  • Updated _generate_and_send_email() to return HTML content for reuse
  • Added _publish_meals_to_website() wrapper function that handles publishing with error notification on failure
  • Updated _send_error_notification() to accept custom subject line for different error types
  • Integrated website publishing into main workflow (skipped in debug mode)
  • Added import for publish_meals_page and WEBSITE_REPO_PATH

Modified: config.py

  • Added WEBSITE_REPO_PATH environment variable configuration
  • Added to __all__ exports for public API

Configuration Changes

  • New optional environment variable: WEBSITE_REPO_PATH - path to website repository for publishing meals page

Testing

The changes integrate with existing error handling and logging infrastructure. Website publishing is:

  • Skipped in debug mode (existing -d flag behavior)
  • Skipped if WEBSITE_REPO_PATH is not configured
  • Wrapped in try-except with error notification on failure
  • Logged at appropriate levels for troubleshooting

Code Quality Checklist

  • ✅ Follows PEP 8 style guide
  • ✅ All functions have type hints
  • ✅ All new functions have docstrings
  • ✅ Error handling with logging and notifications
  • ✅ No hardcoded paths or secrets
  • ✅ Graceful degradation when WEBSITE_REPO_PATH not set

Security Considerations

  • No new security vulnerabilities introduced
  • No hardcoded secrets or credentials
  • Git operations use subprocess with proper error handling
  • HTML content properly escaped in error notifications

Deployment Notes

Pre-deployment:

  • Set WEBSITE_REPO_PATH environment variable to website repository path (optional)
  • Ensure git is available in deployment environment
  • Ensure git credentials are configured for the website repository

Deployment steps:

  1. Deploy code changes
  2. (Optional) Configure WEBSITE_REPO_PATH environment variable
  3. Existing functionality continues to work; website publishing is opt-in

Rollback plan:

  1. Unset WEBSITE_REPO_PATH environment variable to disable website publishing
  2. No database or persistent state changes

Related PRs/Issues

  • Extends existing recipe emailer functionality with website integration

https://claude.ai/code/session_01Nu5ZtcnzQjFsMdYaa7gtpF

Summary by Sourcery

Integrate website publishing of the weekly meals content into the existing recipe emailer workflow.

New Features:

  • Publish the generated weekly meals HTML to a configured website repository after sending the email.
  • Introduce a website-specific meals page generator that wraps email content in the site template and writes meals.html.

Enhancements:

  • Return HTML content from the email generation function so it can be reused for website publishing.
  • Extend error notification handling to support custom subjects and distinguish website publishing failures from other errors.

After sending the email, the script now also generates a meals.html
page for the website repo, commits it, and pushes. Sends an error
email to SENDER if the website publish fails. Set WEBSITE_REPO_PATH
in .env to enable.

https://claude.ai/code/session_01Nu5ZtcnzQjFsMdYaa7gtpF
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 14, 2026

Reviewer's Guide

Implements website publishing for the weekly meals email by returning the generated HTML from the email workflow, wrapping it in a website-specific template inside a new website repository, and committing/pushing the resulting meals.html file, with integrated error handling and configuration via WEBSITE_REPO_PATH.

Sequence diagram for meals email generation and website publishing

sequenceDiagram
    actor User
    participant Main as Main
    participant EmailGenerator as generate_html_email
    participant Mailer as send_email
    participant WebsitePublisher as publish_meals_page
    participant ErrorNotifier as _send_error_notification
    participant Git as git_remote_repo

    User->>Main: main(debug_mode=False)
    Main->>Main: _select_and_prepare_meals
    Main->>Main: _generate_and_send_email
    activate Main
    Main->>EmailGenerator: generate_html_email(context, meals)
    EmailGenerator-->>Main: html_content
    Main->>Mailer: send_email(html_content, debug_mode, SUBJECT)
    Mailer-->>Main: ok
    Main-->>Main: return html_content
    deactivate Main

    Main->>Main: _publish_meals_to_website(html_content)
    alt WEBSITE_REPO_PATH not set
        Main-->>Main: log warning and skip publish
    else WEBSITE_REPO_PATH set
        Main->>WebsitePublisher: publish_meals_page(html_content, WEBSITE_REPO_PATH)
        activate WebsitePublisher
        WebsitePublisher->>WebsitePublisher: generate_meals_page_html
        WebsitePublisher->>Git: git add/commit/push meals.html
        Git-->>WebsitePublisher: success
        WebsitePublisher-->>Main: ok
        deactivate WebsitePublisher
    end

    Main->>Main: _update_tracking_data

    rect rgb(255,230,230)
        Main->>WebsitePublisher: publish_meals_page
        WebsitePublisher-->>Main: exception e
        Main->>ErrorNotifier: _send_error_notification(e, subject)
        ErrorNotifier->>Mailer: send_email(error_html, debug_mode=True, subject)
        Mailer-->>ErrorNotifier: ok
    end
Loading

Class diagram for main workflow and website_publisher functions

classDiagram
    class MainModule {
        +main() void
        +_generate_and_send_email(context: dict~str, Any~, meals: list~dict~str, Any~~, start_time: float, debug_mode: bool) str
        +_publish_meals_to_website(html_content: str) void
        +_send_error_notification(error: Exception, subject: str = Recipe Emailer Error) void
        +_update_tracking_data(context: dict~str, Any~, meals: list~dict~str, Any~~) void
    }

    class WebsitePublisherModule {
        +publish_meals_page(email_html: str, website_repo_path: str) void
        +generate_meals_page_html(email_html: str, website_repo_path: str) str
        +_git_commit_and_push(repo_path: str) void
    }

    class ConfigModule {
        <<module>>
        +WEBSITE_REPO_PATH: str | None
    }

    MainModule --> WebsitePublisherModule : calls publish_meals_page
    MainModule --> ConfigModule : reads WEBSITE_REPO_PATH
    MainModule --> MainModule : calls _send_error_notification on errors
    WebsitePublisherModule --> WebsitePublisherModule : calls _git_commit_and_push internally
Loading

File-Level Changes

Change Details Files
Return HTML content from the email generation step and hook website publishing into the main workflow, with configurable error notifications.
  • Change _generate_and_send_email to return the generated HTML string instead of None and adjust its call site in main to capture this value.
  • Invoke a new _publish_meals_to_website helper after sending the email when not in debug mode.
  • Introduce _publish_meals_to_website to guard on WEBSITE_REPO_PATH, call the website publisher, and send a specialized error notification on failure.
  • Extend _send_error_notification to accept an optional subject parameter and use it both in the HTML body and as the email subject.
main.py
Expose WEBSITE_REPO_PATH as a configurable environment-based setting.
  • Add WEBSITE_REPO_PATH to the module’s public all export list.
  • Define WEBSITE_REPO_PATH as an optional environment-derived constant using os.getenv.
config.py
Add a website publishing module that transforms email HTML into a meals page and pushes it to a Git-backed website repository.
  • Create publish_meals_page to generate meals page HTML from the email HTML, write meals.html into the website repo, and trigger Git commit/push.
  • Implement generate_meals_page_html to extract the contents from the email HTML, embed them in a full-page template that includes navbar, styling, and footer, and load the navbar from templates/navbar.html within the repo.
  • Implement _git_commit_and_push to add meals.html, skip commits when no staged changes exist, and otherwise commit with a dated message and push to the remote, logging progress throughout.
website_publisher.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In generate_meals_page_html, relying on email_html.index('<body>') / index('</body>') will raise a ValueError if the expected tags are missing or differently cased; consider using a more robust approach (e.g., .find with explicit error handling or an HTML parser) so website publishing fails with a clearer, controlled error.
  • When reading navbar.html and writing meals.html, it might be worth validating that website_repo_path and templates/navbar.html actually exist and logging a clear, specific error if they do not, rather than relying on generic file I/O exceptions from the open call.
  • In _git_commit_and_push, failures from the git commands are surfaced only as generic CalledProcessError; wrapping the run_git calls in try/except and logging the underlying stderr would make diagnosing publish failures significantly easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `generate_meals_page_html`, relying on `email_html.index('<body>')` / `index('</body>')` will raise a `ValueError` if the expected tags are missing or differently cased; consider using a more robust approach (e.g., `.find` with explicit error handling or an HTML parser) so website publishing fails with a clearer, controlled error.
- When reading `navbar.html` and writing `meals.html`, it might be worth validating that `website_repo_path` and `templates/navbar.html` actually exist and logging a clear, specific error if they do not, rather than relying on generic file I/O exceptions from the `open` call.
- In `_git_commit_and_push`, failures from the `git` commands are surfaced only as generic `CalledProcessError`; wrapping the `run_git` calls in try/except and logging the underlying `stderr` would make diagnosing publish failures significantly easier.

## Individual Comments

### Comment 1
<location> `website_publisher.py:34-35` </location>
<code_context>
+def generate_meals_page_html(email_html: str, website_repo_path: str) -> str:
+    """Generate a website-compatible meals.html page from email HTML content."""
+    # Extract recipe card content from email HTML body
+    body_start = email_html.index("<body>") + len("<body>")
+    body_end = email_html.index("</body>")
+    recipe_content = email_html[body_start:body_end].strip()
+
</code_context>

<issue_to_address>
**issue:** Using `str.index` on `<body>`/`</body>` assumes the exact tags always exist and will raise unhandled `ValueError` otherwise.

This relies on the HTML containing a single lowercase `<body>`/`</body>` pair with no attributes. If the template changes (e.g., different casing, attributes on `<body>`, or partial HTML), `index` will raise `ValueError` and break the publish step. Consider a more robust approach (e.g., a lightweight HTML parser), or at least use `str.find` plus explicit error handling/logging so failures are handled predictably.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread website_publisher.py
Comment on lines +34 to +35
body_start = email_html.index("<body>") + len("<body>")
body_end = email_html.index("</body>")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Using str.index on <body>/</body> assumes the exact tags always exist and will raise unhandled ValueError otherwise.

This relies on the HTML containing a single lowercase <body>/</body> pair with no attributes. If the template changes (e.g., different casing, attributes on <body>, or partial HTML), index will raise ValueError and break the publish step. Consider a more robust approach (e.g., a lightweight HTML parser), or at least use str.find plus explicit error handling/logging so failures are handled predictably.

@github-actions
Copy link
Copy Markdown

✅ All CI checks passed! Ready for review.

@wassupluke wassupluke merged commit 996f099 into main Feb 14, 2026
10 checks passed
@wassupluke wassupluke deleted the claude/meals-page-from-email-mtbzD branch February 14, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants