Skip to content

Conversation

@iangmaia
Copy link
Contributor

@iangmaia iangmaia commented Aug 4, 2025

What does it do?

This PR adds to the class DerivedBuildCodeFormatter the possibility to configure a versioning prefix instead of always defaulting to 1.

Checklist before requesting a review

  • Run bundle exec rubocop to test for code style violations and recommendations.
  • Add Unit Tests (aka specs/*_spec.rb) if applicable.
  • Run bundle exec rspec to run the whole test suite and ensure all your tests pass.
  • Make sure you added an entry in the CHANGELOG.md file to describe your changes under the appropriate existing ### subsection of the existing ## Trunk section.
  • If applicable, add an entry in the MIGRATION.md file to describe how the changes will affect the migration from the previous major version and what the clients will need to change and consider.

@iangmaia iangmaia self-assigned this Aug 4, 2025
@iangmaia iangmaia added the enhancement New feature or request label Aug 4, 2025
@iangmaia iangmaia marked this pull request as ready for review August 4, 2025 14:32
@iangmaia iangmaia requested review from a team and AliSoftware August 4, 2025 14:32
Comment on lines 42 to 47
# Only trim leading zeros when prefix is empty (to avoid removing explicit "0" prefix)
if @prefix.empty?
result.gsub(/^0+/, '')
else
result
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually not sure how the Google Play API would react to submitting a build with a versionCode that has a leading zero 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iinm, it needs to be an integer in the API so I'd guess they would just be ignored? 🤔 But also considering iOS, perhaps it doesn't make a lot of sense to allow for 0 to be used as prefix (or maybe we should treat it the same as '').

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think doing the gsub unconditionally should be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented on 75f4127.

Comment on lines 76 to 79
# Check if it's within valid range (0-9)
return if prefix_int.between?(0, 9)

UI.user_error!("Prefix must be a single digit (0-9), got: #{prefix_int}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how it'd be technically possible to get to that point in the code and fail that test, given we already ensured that prefix_str would not be a string longer than 1 and would be a valid Integer 😅 🙃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed 😅 Simplified on 49edcb6

#
# @return [String] The formatted build code string.
#
def build_code(build_code = nil, version:)
Copy link
Contributor

@AliSoftware AliSoftware Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not for this PR, but mentioning while I saw it:

Note that this build_code parameter is unused, but was initially still kept here so that the common API for all the *BuildCodeFormatter have the same API (as mentioned in the YARD comment about it), making it easier to switch from one formatter to another without changing the call sites (abstraction layer pattern).

But in practice I just realized that:

  1. We don't have an abstract class for all the *BuildCodeFormatter classes like we have for AbstractVersionFormatter. In fact, the *BuildCodeFormatter classes don't inherit any common parent class, unlike the *VersionFormatter classes
  2. In practice the API for all *BuildCodeFormatter classes is not even consistent (which might actually explain point 1). For example this DerivedBuildCodeFormatter as well as FourPartBuildCodeFormatter indeed both have a signature of def build_code(build_code = nil, version:)… but the SimpleBuildCodeFormatter uses def build_code(version = nil, build_code:) instead…

That makes me think that (1) either one day we should create an abstract class for the *BuildCodeFormatter and unify their API for consistency (2) or we should just abandon the idea of having unified API for all (given the needed input parameters might depend on what the formatter does and needs to compute its value), and remove the unused parameters from the def build_code(…) signatures for clarity… 🙃


Also, in any case, I am surprised that rubocop didn't complain about it and didn't suggest us to rename this parameter with an underscore to indicate that it being unused is intentional (def build_code(_build_code = nil, version:) 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes me thing that (1) either one day we should create an abstract class for the *BuildCodeFormatter and unify their API for consistency (2) or we should just abandon the idea of having unified API for all

Oh, agreed.
I quickly saw the parameter and imagined there would be a base, abstract class like the other versioning formatters.

I am surprised that rubocop didn't complain about it and didn't suggest us to rename this parameter

True 🤔

Comment on lines +99 to +102
it 'rejects symbols and special characters' do
expect { described_class.new(prefix: '@') }.to raise_error(/Prefix must be an integer digit/)
expect { described_class.new(prefix: '#') }.to raise_error(/Prefix must be an integer digit/)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

(this reminded me of this meme 😄 )

Co-authored-by: Olivier Halligon <[email protected]>
Copy link
Contributor

@AliSoftware AliSoftware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting one last unit test but otherwise LGTM so approving to unblock.

class DerivedBuildCodeFormatter
# Initialize the formatter with a configurable prefix.
#
# @param [String] prefix The prefix to use for the build code. Must be a single digit (0-9), or the empty string. Defaults to '1' for backward compatibility.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that funnily enough, I'm not even sure any of our projects use this DerivedBuildCodeFormatter yet 🤔

… So in practice Gravatar-Android would be the first one to use that class iinm 🙃

So I wonder if it's really needed to default to '1' "for backwards compatibility" given this…
On one hand, better safe that sorry and we can always pass a different value at call site in the product's Fastfile. Oh the other hand, if we wanted to change that default prefix, it might actually be now or never 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's true. At some point I also realized that Tumblr used their own implementation but wasn't sure about other apps... and anyway this would be a breaking change of the API technically.

But indeed, in practice it would be nicer to not have this default and avoid this issue in the future (especially if more apps adopt this DerivedBuildCodeFormatter). Shall we do it? I think I'll do it :feelsgood:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in bae9e25

@iangmaia iangmaia merged commit 6486869 into trunk Aug 4, 2025
6 checks passed
@iangmaia iangmaia deleted the iangmaia/derived-build-formatter-enhancements branch August 4, 2025 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants