Skip to content

Clone conference durable workflow - #4822

Open
marcoacierno wants to merge 7 commits into
resonate-ecs-setupfrom
resonate-clone-conference
Open

marcoacierno wants to merge 7 commits into
resonate-ecs-setupfrom
resonate-clone-conference

Conversation

@marcoacierno

Copy link
Copy Markdown
Member

Setting up the next edition means re-creating, by hand, everything that
is configuration rather than content. clone_conference does it in one
Resonate workflow: the conference itself (settings and taxonomies, never
the pretix ids or the logo), then deadlines shifted by the gap between
the two editions' start dates, durations, sponsor benefits/levels/special
options, email templates, generic copy, FAQs, menus, forms and their
questions, and voting included events.

Each copy is a durable step wrapped in a transaction and keyed on the
natural key of what it creates, so a failed run resumes from the step
that failed and re-running never duplicates anything. i18n fields cannot
be used in ORM lookups, so models keyed on one are de-duplicated in
Python.

Content produced during an edition -- proposals, schedule, keynotes,
sponsors, grants, vouchers, answers -- is never copied.

Triggered with manage.py clone_conference <source> <new> ..., whose
workflow id defaults to clone-conference-<new_code>.

What

ToDo

@vercel

vercel Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pycon Ready Ready Preview Sep 26, 2026 1:58pm UTC

@claude

claude Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds a durable Resonate workflow (clone_conference) plus an admin action/form to spin up the next conference edition by copying configuration (deadlines, durations, schedule days, sponsor levels/benefits, email templates, CMS content, forms, voting included events) while leaving edition-specific content untouched.

Bug: cloning collapses multiple custom deadlines into one. copy_deadlines in backend/conferences/workflows/clone_conference.py keys Deadline.objects.get_or_create on (conference, type) only. Deadline.TYPES.custom is explicitly allowed to repeat per conference: validate_deadlines_form in backend/conferences/admin/conference.py skips the "one deadline per type" check specifically when type is custom. So a source conference with several custom deadlines will only have the first one copied; the rest match the already-created (conference, custom) row and are silently dropped. The code already handles this correctly for EmailTemplate (copy_email_templates disambiguates custom templates by name) but the same treatment is missing for copy_deadlines. No test exercises more than one deadline per source conference, so this gap is not caught.

Minor: create_conference and the copy steps annotate new_start/new_end as datetime, but callers (start_clone_conference, and the workflow own clone_conference entrypoint) always pass ISO-format strings. It happens to work because Django DateTimeField parses ISO strings on save, but the type hints are misleading for anyone extending these steps.

@codecov

codecov Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.56198% with 18 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (resonate-ecs-setup@514f7ff). Learn more about missing BASE report.

Additional details and impacted files
@@                  Coverage Diff                  @@
##             resonate-ecs-setup    #4822   +/-   ##
=====================================================
  Coverage                      ?   92.83%           
=====================================================
  Files                         ?      360           
  Lines                         ?    11508           
  Branches                      ?      945           
=====================================================
  Hits                          ?    10684           
  Misses                        ?      703           
  Partials                      ?      121           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Setting up the next edition means re-creating, by hand, everything that
is configuration rather than content. `clone_conference` does it in one
Resonate workflow: the conference itself (settings and taxonomies, never
the pretix ids or the logo), then deadlines shifted by the gap between
the two editions' start dates, durations, sponsor benefits/levels/special
options, email templates, generic copy, FAQs, menus, forms and their
questions, and voting included events.

Each copy is a durable step wrapped in a transaction and keyed on the
natural key of what it creates, so a failed run resumes from the step
that failed and re-running never duplicates anything. i18n fields cannot
be used in ORM lookups, so models keyed on one are de-duplicated in
Python.

Content produced during an edition -- proposals, schedule, keynotes,
sponsors, grants, vouchers, answers -- is never copied.

Triggered with `manage.py clone_conference <source> <new> ...`, whose
workflow id defaults to `clone-conference-<new_code>`.
Creating the next edition is something organizers do from the admin, not
from a shell: selecting the conference to use as base and running *Create
new conference using this one as base* opens a form for the code, name,
hostname and dates of the new edition, prefilled with the same values one
year later, and starts the workflow.

The form refuses a code or hostname already in use, and a start after the
end. Each submission gets its own workflow id so a run that failed for
good can be started again; a double submit is harmless anyway, since
every step of the workflow only creates what is not there yet.
The bare `Resonate()` the tests build picks up RESONATE_URL from the
environment, so in a container that has one they ran against the real
server and replayed promises left by an earlier run instead of executing
the workflow. `env={}` pins them to the in-process connection.
The new edition gets one day per date it runs on, in its own timezone,
and each takes the rooms and slots of the source day in the same
position, so a conference that opens with a workshop day keeps that
shape. Days the source edition did not have are left empty, and the
streaming and Sli.do links stay with the edition that used them.
Every copy step opened with the same four lines: import the models, open a
transaction, and look up the two conferences. A `copy_step` decorator now
does that once and hands each step the source and the new conference, so
what is left in each is only what it copies. `copy_cms_content` covered
three unrelated kinds of content in one long body; it now calls one
function per kind.
The action already refuses anything but a single conference, so passing
the selection to the template as a list -- and the action's own name as a
context variable -- only made the page look more general than it is.
Review follow-ups: the action name the page posts is taken from the
function again, so renaming it cannot leave the form posting an action
that no longer exists (nothing renders this template in tests, so a wrong
name would go unnoticed); the steps keep their qualified name, so a
traceback names the step it came from rather than the decorator; and the
`copied` keys say why they are spelled out instead of derived.
@marcoacierno
marcoacierno changed the base branch from resonate to resonate-ecs-setup September 26, 2026 13:54
@marcoacierno
marcoacierno force-pushed the resonate-clone-conference branch from 84ddcd4 to 3bb145a Compare September 26, 2026 13:54
@marcoacierno
marcoacierno added this pull request to stack #4826 September 26, 2026 13:54

This branch was successfully deployed

1 active deployment
Preview — 3bb145a6 Deployed Sep 26, 2026 by vercel[bot]
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.

1 participant