• 
      

    Sync default bug trackers from legacy settings on save.

    Review Request #15340 — Created Sept. 24, 2026 and updated

    Information

    Review Board
    release-9.x

    Reviewers

    Repository.save() now keeps the legacy bug tracker fields and
    default_bug_tracker in sync, so a repository never has legacy bug
    tracker settings without a default bug tracker, regardless of which code
    path wrote them:

    • A direct write of the legacy bug_tracker URL template (deprecated,
      with a warning) gets or creates a matching custom configuration and
      assigns it as the default. An empty value clears the default. The
      repository form composes and writes that template on the user's
      behalf, so it suppresses the warning for its own save.

    • Hosting-based settings written to extra_data
      (bug_tracker_use_hosting or bug_tracker_type) are synced after the
      save, since their configurations are scoped to the repository ID. A
      manually-assigned default is never replaced.

    • An assigned default regenerates the legacy template for older
      consumers.

    New tests cover the repository form's save path: a hosting-based bug
    tracker gets a configuration bound to the account and scoped to the
    repository, and neither the hosting nor the custom URL case emits the
    deprecation warning.

    The migration tests now stop the save-time sync while building their
    repositories, so the stored legacy state reaches the migration
    functions untouched.

    Ran unit tests.

    Summary ID
    Sync default bug trackers from legacy settings on save.
    `Repository.save()` now keeps the legacy bug tracker fields and `default_bug_tracker` in sync, so a repository never has legacy bug tracker settings without a default bug tracker, regardless of which code path wrote them: * A direct write of the legacy `bug_tracker` URL template (deprecated, with a warning) gets or creates a matching custom configuration and assigns it as the default. An empty value clears the default. The repository form composes and writes that template on the user's behalf, so it suppresses the warning for its own save. * Hosting-based settings written to `extra_data` (`bug_tracker_use_hosting` or `bug_tracker_type`) are synced after the save, since their configurations are scoped to the repository ID. A manually-assigned default is never replaced. * An assigned default regenerates the legacy template for older consumers. New tests cover the repository form's save path: a hosting-based bug tracker gets a configuration bound to the account and scoped to the repository, and neither the hosting nor the custom URL case emits the deprecation warning. The migration tests now stop the save-time sync while building their repositories, so the stored legacy state reaches the migration functions untouched. Testing Done: Ran unit tests.
    zozvrozyqykmvkyknqlvuznmkvtywnnn
    Description From Last Updated

    I think we don't need this .exists() check here, .add() will only add the relation if it doesn't exist already, …

    maubin maubin
    maubin
    1. 
        
    2. Show all issues

      I think we don't need this .exists() check here, .add() will only add the relation if it doesn't exist already, so this is just an extra query. Can probably just change this to an else?

    3. 
        
    david
    Review request changed
    Commits:
    Summary ID
    Sync default bug trackers from legacy settings on save.
    `Repository.save()` now keeps the legacy bug tracker fields and `default_bug_tracker` in sync, so a repository never has legacy bug tracker settings without a default bug tracker, regardless of which code path wrote them: * A direct write of the legacy `bug_tracker` URL template (deprecated, with a warning) gets or creates a matching custom configuration and assigns it as the default. An empty value clears the default. The repository form composes and writes that template on the user's behalf, so it suppresses the warning for its own save. * Hosting-based settings written to `extra_data` (`bug_tracker_use_hosting` or `bug_tracker_type`) are synced after the save, since their configurations are scoped to the repository ID. A manually-assigned default is never replaced. * An assigned default regenerates the legacy template for older consumers. New tests cover the repository form's save path: a hosting-based bug tracker gets a configuration bound to the account and scoped to the repository, and neither the hosting nor the custom URL case emits the deprecation warning. The migration tests now stop the save-time sync while building their repositories, so the stored legacy state reaches the migration functions untouched. Testing Done: Ran unit tests.
    zozvrozyqykmvkyknqlvuznmkvtywnnn
    Sync default bug trackers from legacy settings on save.
    `Repository.save()` now keeps the legacy bug tracker fields and `default_bug_tracker` in sync, so a repository never has legacy bug tracker settings without a default bug tracker, regardless of which code path wrote them: * A direct write of the legacy `bug_tracker` URL template (deprecated, with a warning) gets or creates a matching custom configuration and assigns it as the default. An empty value clears the default. The repository form composes and writes that template on the user's behalf, so it suppresses the warning for its own save. * Hosting-based settings written to `extra_data` (`bug_tracker_use_hosting` or `bug_tracker_type`) are synced after the save, since their configurations are scoped to the repository ID. A manually-assigned default is never replaced. * An assigned default regenerates the legacy template for older consumers. New tests cover the repository form's save path: a hosting-based bug tracker gets a configuration bound to the account and scoped to the repository, and neither the hosting nor the custom URL case emits the deprecation warning. The migration tests now stop the save-time sync while building their repositories, so the stored legacy state reaches the migration functions untouched. Testing Done: Ran unit tests.
    zozvrozyqykmvkyknqlvuznmkvtywnnn

    Checks run (2 succeeded)

    flake8 passed.
    JSHint passed.
    maubin
    1. Ship It!
    2.