-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Run genstrings in CI to validate LocalizedString usages
#19553
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
Conversation
This will allow us to run the lane in CI without changing the repo state, even though that's something that wouldn't be pushed.
genstrings in CI to validate LocalizedStrings usagesgenstrings in CI to validate LocalizedString usages
| install_gems | ||
|
|
||
| echo "--- :cocoapods: Setting up Pods" | ||
| install_cocoapods |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line made me go down a rabbit hole thinking about whether we can optimize how we generate the pods cache further #19551.
| # Runs the `.strings` generation automation to ensure all the | ||
| # `LocalizedString` calls in the code can be correctly parsed by Apple's | ||
| # `genstrings`. | ||
| - label: "Lint Localized Strings Format" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not feeling super inspired here tbh… Maybe Lint L10n Strings Format just so it can fit? 🤷
Generated by 🚫 dangerJS |
| cp -v fastlane/env/project.env-example ~/.configure/wordpress-ios/secrets/project.env | ||
|
|
||
| echo "--- Lint Localized Strings Format" | ||
| bundle exec fastlane generate_strings_file_for_glotpress skip_commit:true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm debating whether to put in the time to somehow capture the genstrings error, if any, and to annotate the build with it, vs banking on this to be a low occurrence kind of failure and accepting a less polished UX.
There was a problem hiding this comment.
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 easy it would be to capture the error from genstrings here anyway 🤔
Maybe one easy way would be to store the logs of bundle exec fastlane command (e.g. | tee logs.txt) then grep for genstrings: error: lines in it?
bundle exec fastlane generate_strings_file_for_glotpress skip_commit:true | tee genstrings-logs.txt
if [[ $? -ne 0 ]]; then
# Previous step errored, extract the errors in an easy-to-find section
echo "--- Report genstrings errors"
echo "Found errors when trying to run genstrings to generate the `.strings` files from `*LocalizedStrings` calls."
echo "See below for a summary (or previous section for more details)."
grep 'genstrings: ' 'genstrings-logs.txt'
grep 'genstrings: ' 'genstrings-logs.txt' | buiildkite-agent annotate --style error --context genstrings
fi
If that works, that could be an easy enough addition to the script without too much complication. If that doesn't work, then probably not worth spending too much time on it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I'll have a go a it.
I didn't go down the piping output option because I didn't want to lose the logs in the Buildkite UI. I had forgotten about the tee command 🤦♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AliSoftware addressed in 5e355c3.
What do you think of extracting this in the Buildkite plugin? I don't like how it depends on a lane name, which could vary across projects. But... we have a lot of convention over configuration already, and we can have proper error messages around that in the plugin command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea to extract in plugin commands.
I agree that we have a lot of convention over configuration but I'm not sure the name of this lane is one that is currently consistent across repos at the moment 🤔 Maybe we can accept the lane name as optional parameter (${1:-generate_strings_file_for_glotpress}) to cover our backs (instead of failing if convention isn't followed in a repo)?
You can test the changes in Jetpack from this Pull Request by:
|
You can test the changes in WordPress from this Pull Request by:
|
| # Fastlane uses to color the output. | ||
| grep -e "\[.*\].*genstrings:" $LOGS \ | ||
| | sed -e 's/\[.*\].*genstrings: error: /- /' \ | ||
| | sed -e $'s/\x1b\[[0-9;]*m//g' \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about moving this one sed on the line that pipes to buildkite-agent annotate instead? That way we'd still have colors included in the tee'd logs sent to stdout and only remove the ANSI codes from the annotation 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, without that filter, we get a double match for one of the errors.
Take the colored output in the following screenshots:
When run through the code without the ANSI color RegEx, it returns
Found errors when trying to run `genstrings` to generate the `.strings` files from `*LocalizedStrings` calls:
- bad entry in file WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Search.swift (line = 50): Argument is not a literal string.
- bad entry in file WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Search.swift (line = 50): Argument is not a literal string.
- bad entry in file WordPress/Classes/ViewRelated/Aztec/Extensions/Header+WordPress.swift (line = 28): Argument is not a literal string.
As far as I can tell, the reason is because of different terminators between the errors printed in line and the ones at the end of the Fastlane execution. With cat -e, we can see
[05:19:23]: ^[[32m-------------------------------------------------^[[0m$
[05:19:23]: ^[[32m--- Step: ios_generate_strings_file_from_code ---^[[0m$
[05:19:23]: ^[[32m-------------------------------------------------^[[0m$
[05:19:23]: �M-^V� ^[[35mgenstrings: error: bad entry in file WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Search.swift (line = 50): Argument is not a literal string.^[[0m$
[05:19:23]: �M-^V� ^[[35mgenstrings: error: bad entry in file WordPress/Classes/ViewRelated/Aztec/Extensions/Header+WordPress.swift (line = 28): Argument is not a literal string.^[[0m$
+------------------+-----------------------------------------+$
| ^[[33mLane Context^[[0m |$
+------------------+-----------------------------------------+$
| DEFAULT_PLATFORM | ios |$
| PLATFORM_NAME | ios |$
| LANE_NAME | ios generate_strings_file_for_glotpress |$
+------------------+-----------------------------------------+$
[05:19:26]: ^[[31mgenstrings: error: bad entry in file WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Search.swift (line = 50): Argument is not a literal string.$
genstrings: error: bad entry in file WordPress/Classes/ViewRelated/Aztec/Extensions/Header+WordPress.swift (line = 28): Argument is not a literal string.^[[0m$
[05:19:26]: ^[[31mfastlane finished with errors^[[0m$
You can see that the second bad entry in file WordPress/Classes/Extensions/Colors and Styles/WPStyleGuide+Search.swift (line = 50)... doesn't have the ^[[0m$ suffix. I'm guessing that's because Fastlane prints all the errors it collected in a single colored expression, but with new lines. The fact that there's only one [05:19:26] timestamp annotation for both errors at the end of the logs points to that, too.
I'm sure there's a RegEx we can write to work around all this, but it sounds like we'd be hitting the diminishing return threshold.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, I see. Tricky. Nice catch.
Let's keep the filter to remove ANSI code early in the command like you did then.
Besides, even if we managed to keep the colors while still properly removing duplicates, I don't think there's any case where those error lines use multiple styles (e.g. multiple colors / boldness / … within the line to emphasis some words), and instead all the lines seems to all be in a single style each… either all red or all purple. So we wouldn't end up benefit from keeping the coloring much (and even if we wanted those to appear red in the the stdout of the dedicated section to make them stand out, we could always re-add the red-color-ANSI-code around it all manually ourselves 🤷 ). So not worth keeping the initial ANSI-codes after all indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh, the nicer solution would probably be to have generate_strings_file_for_glotpress handle the "write-errors-to-file" capability:
- Either by providing the right options or indirections from the implementation of the action itself when it calls
genstrings(something likegenstrings -o Localizable.strings $files 2>genstrings-stderr.log—or maybe something a bit more convoluted to usetee, but onstderrand notstdout, ifgenstringsprints those warnings tostdout?—, where thegenstrings-stderr.logfile name would be provided by aConfigItemdefaulting tonil?), which would probably be the cleanest solution, but would require updating the action itself in release-toolkit to add such support - Or by updating the
generate_strings_file_for_glotpresslane in yourFastfileto redirect just the output of the call toios_generate_strings_file_from_codeaction into a log file (instead of the output of the whole fastlane invocation, which includes that but also all the ceremony with lane switch header, Lane Context table, and summary lines at the end)
And then parse that file to detect and extract the genstrings warnings, without those parsed logs being cluttered by other fastlane logs.
Only drawback I see from that is that the plugin command (that this script would be turned into) would have to rely on you not only have a generate_strings_file_for_glotpress lane, but also for you to have it invoke ios_generate_strings_file_from_code with the proper log file name to write to, so that means relying a lot on conventions being followed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mokagio How do you want to go forward with this PR?
- Address the above feedback (i.e. move the "write to file redirect" to just the call on
generate_strings_file_for_glotpressinstead of the wholefastlanerun, or update our action in release toolkit to add someConfigItem(key: :errors_log_file)to it etc) in this PR? - Or merge as is, and address this improvement in a follow-up PR?
- Or merge as is, and migrate that logic to a dedicated command in
bash-cachein follow-up PRs, improving it / addressing above feedback in there later too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AliSoftware thanks for asking.
Or merge as is, and migrate that logic to a dedicated command in
bash-cachein follow-up PRs, improving it / addressing above feedback in there later too?
It's, sort of, the best of both worlds. We have something that works and we can ship ASAP, then we can iterate from a centralized place.
I say "sort of", because if we go down the path of updating the toolkit, we either use a default value for the log files or we'd have to update all the clients again.
Still, give this has the possibility of preventing some issue, I'd say let's ship as is ASAP to get more coverage, then improve on the setup.
|
Side note that even with this in place, we might still miss issues with Not sure if there are other options / ideas to detect those kind of cases and to be sure to not miss any other. |
The only thing I can think of is to be strict and require every |
|
@crazytonyli recently played around with That use case of enforcing |
These changes had already been discussed in wordpress-mobile/WordPress-iOS#19553 and applied in the test PR used for it, but I forgot to cherry pick them back on the original one. Once I copied the script over to this project, I did it from the branch without the improvements.



The 21.0 code freeze was delayed because of a
LocalizedStringthat didn't use strings literals and therefore failed thegenstringsexecution. See #19473.The change had been in the codebase for a while, but we only found out at code freeze time.
To make the feedback loop faster, this PR adds a new CI step that runs the lane that generates the
.stringsto make sure everything runs fine.Important Once this is merged into
trunk, we ought to make the check a required one in the GitHub settings fortrunkandrelease/*. I updated the internal document for this work, pdnsEh-Ly-p2, to remind me about it.Implementation Note
This check requires a macOS agent, because of
genstrings. We can run it in the “Build for Testing” step, before even starting the time consuming build, or in a dedicated step.The first option saves resources, the second gives developers more feedback by means of showing whether the app builds and the tests pass regardless of the
genstringsstatus.Since we want to optimize for developer productivity, I opted for a dedicated step instead of making
genstringsa precondition for "Build for Testing".Testing
See #19544 which intentionally introduces a failure
Regression Notes
RELEASE-NOTES.txtif necessary. N.A.