feat: implement Obsidian publishing pipeline (export/sync/validate) and CI integration#5
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c59a74b113
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for post_file in sorted(posts_dir.glob("*.md")): | ||
| if is_generated_post(post_file) and post_file.name not in managed_posts: | ||
| post_file.unlink() |
There was a problem hiding this comment.
Prevent deleting all generated posts on empty export
This deletion loop removes every generated _posts/*.md whenever managed_posts is empty, which occurs if export runs with no publishable vault notes (including CI runs where vault/20-Posts is absent). In that case the workflow still proceeds and deploys a site with all previously generated posts removed, even though repository _posts content may have been valid before running the pipeline.
Useful? React with 👍 / 👎.
| if not dst.exists() or src.read_text(encoding="utf-8") != dst.read_text(encoding="utf-8"): | ||
| shutil.copy2(src, dst) | ||
|
|
||
| managed_asset_slugs = {Path(data["assets_dir"]).name for data in index.values()} |
There was a problem hiding this comment.
Delete stale asset dirs when a post drops embeds
managed_asset_slugs is built from .index.json entries for all posts, not from actual exported asset directories. If a post previously had embeds but now has none, its slug remains in the index so cleanup skips removing assets/img/posts/<slug>, and old files stay publicly served indefinitely.
Useful? React with 👍 / 👎.
Motivation
Description
tools/publishing/publish.pyimplementing three subcommands:export(scanvault/20-Posts, requirepublish: true, convert wikilinks and embeds, copy assets, writesite-content/.index.json),sync(syncsite-content→_postsandassets/img/postswhile only deleting files/assets marked as generated), andvalidate(front matter checks, slug/post conflicts, unresolved links, missing embeds, sensitive-pattern scanning).tools/publishing/{export.sh,sync-to-jekyll.sh,validate.sh}to standardize local/CI invocation and use a generated marker (generated_byfront matter and an asset marker file) to avoid modifying manual content.validate -> export -> syncbeforebundle exec jekyll b, and update_config.ymland.gitignoreto excludevaultandsite-contentfrom Jekyll and to ignore Obsidian metadata.docs/publishing-pipeline.mdexplaining the recommended directory layout, publishing filter rules, export/sync paths, resource strategy, link rewriting approach and rollback guidance.Testing
python3 tools/publishing/publish.py --helpwhich printed the CLI help successfully.python3 -m py_compile tools/publishing/publish.pywhich completed with no syntax errors.python3 tools/publishing/publish.py validatewhich returned "Validation passed for 0 post(s)" because there were no publishable notes in this environment.validate,export,sync) which completed successfully and producedsite-content(exported 0 posts in this repo context), confirming the commands execute in the repository environment.Codex Task