Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change templates to one branch per Briefcase version #824

Closed
mhsmith opened this issue Aug 15, 2022 · 3 comments
Closed

Change templates to one branch per Briefcase version #824

mhsmith opened this issue Aug 15, 2022 · 3 comments
Labels
enhancement New features, or improvements to existing features.

Comments

@mhsmith
Copy link
Member

mhsmith commented Aug 15, 2022

It's occurred to me that the Chaquopy template PR (beeware/briefcase-android-gradle-template#52) won't be compatible with old versions of Briefcase, because its briefcase.toml omits app_support_path, and replaces app_packages_path with app_requirements_path. The Flatpak template did both of these things too, but that was no problem because old versions of Briefcase didn't support Flatpak anyway.

The issue of it being difficult to update the templates without breaking old versions of Briefcase has come up several other times in the last couple of months, most recently at #804 (comment). So I'd like to revisit the idea of a closer coupling between the Briefcase version and the template version,, which we previously discussed at #775 (comment):

there are significant differences in the iOS and macOS templates between versions. [...] The macOS App template has an embedded binary which is, by definition, Python version dependent. [...] On top of that, I'm working on #629 right now which will (hopefully) add a stub binary for Windows

Here are the differences between the 3.9 and 3.10 branches of each current template:

  • android-gradle: none
  • ios-Xcode: one string in a .m file
  • linux-appimage: none
  • linux-flatpak: none
  • macOS-app: one binary
  • macOS-Xcode: one string in a .m file
  • windows-app: one binary
  • windows-VisualStudio: one string in a .cpp file

The strings are obviously easy to template. For the binaries, we can make the template contain them all side by side, with Python version numbers in their names, and provide a cookiecutter "post" hook which renames one of them to the target name and removes all the others. From the perspective of Briefcase, the cookiecutter output would be exactly the same as it is now.

the existence of a 3.X branch is a way for us to gate whether we support [Python] 3.X in apps

This could be done by a cookiecutter "pre" hook.

Embedding the template hash/tag for a specific version in the Briefcase code would be one way to address this; but that would limit our ability to make smaller hot fixes to the template (or, at least, it would make hot fixes more difficult).

In general I think we should avoid making hot fixes which affect already-released versions of Briefcase, as it makes app builds non-reproducible. Even if a hot fix doesn't actually break anything, if users notice that their app is constantly changing underneath them despite them staying on the same Briefcase version, it'll make them unwilling to trust us as the foundation of a serious project.

However, if we used a branch rather than a tag, then that would still leave us the option of making hot fixes, as well as making development more convenient:

  • Increment the Briefcase version number in the repository immediately after a release, e.g. it should currently be 0.3.9.
  • Rename the "dev" branch on each template to "0.3.9", and make it compatible with all Python versions as described above.
  • When Briefcase 0.3.9 is released, we create new template branches for the next version (initially pointing at the same commit as the previous version), and make them the default branch on GitHub. We'd still have the option of pushing bug fixes to the old template branches, but I don't think we'd need to do that very often, and then probably only to the current stable version.

The top-level briefcase-template doesn't currently have multiple branches, but since it also receives updates to support new Briefcase features (e.g. beeware/briefcase-template#31, which accidentally broke AppImage builds), it would make sense to handle that in exactly the same way.

Advantages of this scheme:

  • There would be no need to constantly merge between 5 parallel branches, so the commit history of each template would mostly be linear and easy to follow.
  • It would avoid the need to ask whether every template update is compatible with every old version of Briefcase. Even if it is compatible, convincing ourselves of that is still a drag on our time, because we can't feasibly test every version of Briefcase every time we update a template. And if it's not compatible, we waste even more time coming up with an alternative approach. Either way, as time goes by and more Briefcase versions are in use in the wild, template updates will become progressively more difficult. Whereas if each version of the template only needs to support one version of Briefcase, we have a lot more flexibility to update it.
@mhsmith mhsmith added the enhancement New features, or improvements to existing features. label Aug 15, 2022
@freakboy3742
Copy link
Member

These are all valid points; there's clearly a need to do something about Briefcase version compatibility. Reproducibility of builds in particular is a definite concern that I have. At least in the short term, I'm comfortable telling users "fix problems by updating everything"; but as we mature as a project, I agree that becomes less viable as a strategy.

Your analysis of template differences is correct AFAICT for 3.9->3.10 templates; however, that's an example of a Python version update where not much changed. You see much more substantial changes if you look at 3.7->3.8. That version update included 2 major themes in template changes:

  1. The Python library for 3.7 included an m suffix (libpython3.7m.so); that suffix has been dropped in later versions
  2. The code required for bootstrapping the Python app is radically different.

(1) is a relatively minor inconvenience; it's annoying, but it shouldn't be too hard to add an {% if version < 3.8 %} template block wherever the library name is mentioned; (2) is the bigger concern. The PyConfig APIs aren't available in Python 3.7; and the older Py_SetPythonHome() et al are removed in Python 3.11. This means we need completely different code to start up the Python interpreter - the same basic steps are all there, but the actual code (and even the ordering of that code) is radically different. This bootstrapping code has been reasonably stable since 3.8; but in the 3.4-3.7 timeframe, changes in this bootstrapping code (of varying degrees of complexity) was common. We don't really have any way to predict if this will change in future, and if it does, how big those changes will be. I guess we could use one big block of template logic that has entire bootstrap implementations in the .py file. That makes editing template updates painful, but I guess it would work at an end-user level.

Regarding the specific implementation approach - my inclination would be slightly different to what you propose. Instead of cutting a branch at the start of development of a new Briefcase release, I'd suggest we use a "release branch" approach. We maintain a dev/main branch which remains the "bleeding edge" against which PRs are merged. When it comes time to make a Briefcase release, we cut a 0.3.X release branch from the current tip of main.

This means we don't need to commit to our next version number at the start of the development cycle, and we don't have to handle .dev version prefixes. For internal development purposes, we (i.e., developers of Briefcase) would use template_branch='main' in test projects and in CI; part of the release testing process would be to drop that definition so that CI can run against the default behavior, which would be to use the Briefcase version as the template branch. We can still make "bug fix" updates to template branches if necessary - in many cases, those updates will likely be cherry-picks of commits on main.

FWIW: there's a related set of concerns around the support packages. Although those generally only vary as a result of updates to Python (or other key libraries), very occasionally we need to make changes to the structure of those packages, and those structural changes are usually accompanied by template changes. For example, the changes I'm currently looking at for binary module compatibility on iOS will likely result in significant changes to the iOS and macOS support packages - and will require parallel changes to the iOS and macOS templates (both Xcode and App). I think we may need to include an allowance in templates to set a min/max support package version so that we can publish a support package version update without the risk of breaking compatibility with older template versions.

@mhsmith
Copy link
Member Author

mhsmith commented Aug 16, 2022

After discussion, we agreed the following:

  • Constantly changing the default GitHub branch would make it too easy to merge PRs to the wrong branch and affect an already-released version of Briefcase, so we should use main for development. There would no longer be any need to have a separate dev and main.
  • Make Briefcase automatically detect its own version number using something like setuptools-scm. If it detects it's on a development version, its default template branch will be main; otherwise, it'll correspond to the Briefcase version number. That way, there's no need to manually reconfigure every test project to use the development branch.
  • When it comes time to make a Briefcase release, we create a tag in the Briefcase repository, and cut a 0.3.X release branch from the current tip of main in each template repository. Because the tagged version of Briefcase will use these branches, the pre-release tests will ensure we don't forget to create them.

We'll hold off on doing this until we know exactly what template changes come out of the current work on iOS, macOS and Android.

@mhsmith
Copy link
Member Author

mhsmith commented Aug 16, 2022

One more thought: if Briefcase detects a development version number like 0.3.9.devX or 0.3.9+dYYYYMMDD, it should still attempt to use a 0.3.9 template branch before falling back on main. Otherwise, checking out an old Briefcase commit for comparison would be inconvenient, because it would use the current development template, which is unlikely to work.

But if Briefcase detects a clean tagged version number like 0.3.9, it should never fall back on main, because a released version should only use a release branch. As mentioned above, the pre-release tests will verify that the branches have all been created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

No branches or pull requests

2 participants