Publication

By default, every save in Emet is a commit to the branch you’re editing, and if that branch is the one your site deploys from, the change is live as soon as the build finishes. For a personal blog that’s fine. For a site with more than one editor, or one where someone needs to sign off before things go public, it’s a bit terrifying.

The publication workflow adds a step. You edit on a working branch, and when you’re ready, Emet opens a pull request to a production branch and lets you merge it once the checks pass. Your deploy pipeline watches production and nothing goes live until that merge.

Why pull requests?#

Because GitHub already has everything a review step needs: diffs, comments, approvals, required checks, branch protection. Rather than build a parallel approval system inside Emet, the workflow drives GitHub’s, and surfaces enough of it in the CMS that editors don’t need to open GitHub themselves. Anyone who does prefer GitHub’s UI can use it; the PR is a normal PR.

Configuration#

Set production_branch at the top level of admin/site.yaml:

production_branch: main
working_branch: staging
allowed_branches: [staging, main]
publish:
  merge_method: squash
Key What it does Default
production_branch The branch your site deploys from. Setting this turns the workflow on. unset
working_branch The branch editors land on after sign-in. the repository’s default branch
allowed_branches Branches offered in the branch switcher. all branches
publish.merge_method squash, merge or rebase. squash

The setup wizard writes all of these if you tick Enable review workflow. Despite the name, that’s this branch-and-pull-request flow, not entry review.

The workflow is only active when the branch you’re editing differs from production_branch. Switch to the production branch and the Sync with Production button disappears, and saves go straight to production again.

Submitting changes#

Edits are committed to the working branch as you save. The header button Sync with Production shows how many commits the working branch is ahead of production, and spins while a save is on its way to GitHub.

Click it and you get the list of changed files, each expandable to show its diff, plus optional title and description fields for the PR. The title defaults to “Content updates”. Submit for Review first pushes anything the sync service still has queued, then opens the pull request.

There’s only ever one open PR from the working branch to production. Further saves on the working branch add to it, and the button changes to show the PR’s state instead of a count: Ready when it can be merged, Pending while checks run or reviews are outstanding, Changes if a reviewer has requested changes, or Review if someone else opened the PR and it’s waiting on you.

Merging#

With a PR open, the modal shows:

  • A status banner: ready to go live, waiting for branch protection requirements, merge conflicts, failed checks, or branch behind base. Conflicts and a stale branch have to be sorted out on GitHub; everything else is visible here.
  • The PR title, description and the changed files with their diffs. Review threads appear inline at the lines they refer to; you can start a thread on any line, reply, and resolve or unresolve. Threads refresh every 15 seconds while the modal is open.
  • Branch protection rules, required reviews, status checks and GitHub Actions workflow runs, each with a link to the run on GitHub.
  • Deployments, if your host reports them to GitHub. When exactly one has a preview URL, a View Staging Site button appears next to the merge button.
  • General PR comments, and a box to add one (Ctrl+Enter to post).

If you opened the PR, there’s a reviewer picker for requesting reviews from collaborators. If someone else did, you get Approve, Request Changes and Comment buttons instead, which submit a proper GitHub review.

Go Live merges the PR with the configured method. It’s disabled until GitHub says the PR is mergeable, so required checks and approvals are enforced even for people who’d rather click through them.

After the merge#

Once the merge goes through, Emet force-updates the working branch to match production and clears its local cache, so your next round of edits starts from exactly what’s live. Note that this overwrites the working branch: anything committed to it outside the PR (which shouldn’t happen if everyone’s using Emet, but might if someone pushed by hand) will be gone.

If the branch reset fails, the modal stays open and says so. Your changes are live either way; it’s just that Emet will keep showing already-published edits as unpublished until the branch is reset. There’s a Retry Reset button, or you can reset the branch on GitHub.

Comments in the editor#

When the entry you have open has review threads on the current PR, a Comments tab appears in the editor’s right panel. Threads on body lines link to the line, and in Markdown mode there’s a gutter marker with the comment count that jumps there. Threads on frontmatter lines are labelled Front matter, file-level comments File, and threads whose lines have since changed Outdated. Resolved threads are grouped separately.

Replying and resolving happen in the publish modal; the tab links straight to it.

Reviewing entries one at a time#

The pull request reviews the whole branch in one go. If your team wants to sign off on each page separately, turn on entry review: every entry gets its own review state, and Go Live stays disabled until every changed entry in the pull request has been approved.

Polling#

Emet doesn’t get webhooks, so it polls. While the publish modal is open with a PR, it checks merge readiness every 2.5 seconds while GitHub is still working out mergeability, every 4 seconds while checks or deployments are running, and every 30 seconds once things have settled. With the modal closed it checks the comparison every minute and the PR itself every 5 to 60 seconds depending on activity, so the header button stays roughly current without hammering the API.

In practice#

  1. Edit on the working branch. Save as normal.
  2. Click Sync with Production and Submit for Review.
  3. Wait for checks, or for a colleague to approve.
  4. Click Go Live.
  5. Your site deploys from production. The working branch is reset to match.