I think this is a great example of where build systems, that understand the need for testing, can help out. In a build system I use quite often (Bazel) you can express this as an `sh_test()` [0] which provides documentation about what you're attempting to do <i>and</i> provides you with a way to reproduce the failure locally. You don't have to push the code and wait for CI to fail to find out, or debug, this error.<p>Extra fun thing to do: print a message describing why the decision was made and how to resolve the error in the failure message of your test!<p>[0] - <a href="https://docs.bazel.build/versions/main/be/shell.html#sh_test" rel="nofollow">https://docs.bazel.build/versions/main/be/shell.html#sh_test</a>
In today's world of excellent CLI tools I don't think grep is a good choice, especially for checking irregular languages like XML. [0]<p>I use tools like `jq` [1] or `yq` [2] all the time for CI checks. One useful check, is we have a configuration file stored as several hundred lines of YAML. Its a nice thing to maintain a sorted order for that, so we have a git pre-commit hook that runs the following:<p>> yq eval --inplace '.my_key|= sort' my_file.yaml<p>Of course, a pre-commit hook or CI both work. There's pros and cons of both. For our team, the pre-commit hook is a low enough level of effort, and doesn't require a CI check for something that executes in milliseconds.<p>[0] <a href="https://stackoverflow.com/a/1732454" rel="nofollow">https://stackoverflow.com/a/1732454</a><p>[1] <a href="https://github.com/stedolan/jq" rel="nofollow">https://github.com/stedolan/jq</a><p>[2] <a href="https://github.com/mikefarah/yq" rel="nofollow">https://github.com/mikefarah/yq</a>
Here is my favorite: <a href="https://github.com/ClickHouse/ClickHouse/blob/master/utils/check-style/check-style#L251" rel="nofollow">https://github.com/ClickHouse/ClickHouse/blob/master/utils/c...</a><p>"Too many exclamation marks"
> I personally prefer ripgrep as it is much faster than grep, but usually that is not available on CI machines.<p>I recommend git grep, which is comparable in speed to ripgrep, since it ignores non-tracked files and searches the object storage directly. It is also able to run in parallel.
The semgrep[1] tool seems like the logical next step, for when you've outgrown plain ol' grep.<p>[1] <a href="https://semgrep.dev/" rel="nofollow">https://semgrep.dev/</a>
Android's default linting already contains a "missing translation" lint rule which you can activate: "MissingTranslation"[0]<p>For Android specifically: Gradle and Android Studio both support a powerful linting framework (to the level that it can provide auto-fixes to the IDE). It's better to provide an in-editor to guide your contributors before it hits CI, then have CI nag if they didn't fix the in-editor warnings/errors:<p>Some examples of custom lint rules[1] and the default rules which Android Studio runs[2]:<p>[0] <a href="https://android.googlesource.com/platform/tools/base/+/32923407563b7e2c943cf372e3cd9d4398d09789/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java#79" rel="nofollow">https://android.googlesource.com/platform/tools/base/+/32923...</a><p>[1] <a href="https://github.com/ankidroid/Anki-Android/tree/master/lint-rules/src/main/java/com/ichi2/anki/lint/rules" rel="nofollow">https://github.com/ankidroid/Anki-Android/tree/master/lint-r...</a><p>[2] <a href="https://github.com/ankidroid/Anki-Android/blob/master/lint-release.xml" rel="nofollow">https://github.com/ankidroid/Anki-Android/blob/master/lint-r...</a>
Don't you worry about what happens when the translation software produces a semantically equivalent empty string, or something? Like `<string><![CDATA[]]></string>`. An XML parser will find that to be empty, grep will be like "ooh lots of text in there".
If you think of a CI configuration as a shell script, then this is normal and not surprising.<p>A CI config is just a big job that invokes a bunch of tools like "go build" or "npm test", which is exactly what a shell script is too. I would get rid of the YAML and use shell for the whole thing :)<p>Shell does have some problems, like needing to be more parallel, incremental, and reproducible, but the YAML-based CI systems all have those problems too.<p>Related: <a href="http://www.oilshell.org/blog/2021/04/build-ci-comments.html#ci-services-as-a-bridge-between-shell-and-distributed-systems" rel="nofollow">http://www.oilshell.org/blog/2021/04/build-ci-comments.html#...</a> (and the entire post)
Wouldn't quick sanity checks like these make more sense in a git push hook?<p>No reason to wait for the CI. There's also the risk of broken intermediary commits unless the CI check each and every commit in isolation.
Shameless plug: if you find yourself wanting more advamced custom painting, you can try <a href="http://trunk.io" rel="nofollow">http://trunk.io</a>, which provides you with three different ways to write your own linters (pass/fail based on your script's exit code, spit out a patch that should be applied to your code, or LSP diagnostics) that can get propagated to VSCode and CI (as well as just as a CLI tool, if that's your preference).<p>Disclaimer: I work on trunk :)
Interesting to see how nobody cares about exit code 2. Modify your grep command to have syntax error and you will always think you have all the translations.<p>Edit: ah.. forgot the whole point.. In Next Generation Shell (author here) this doesn't happen: ngs -e '$(grep ...).not()' does right thing. grep exit code 0 becomes 1, 1 becomes 0, 2 becomes 240 (exception)
grep and other shell tool one-liners also make excellent kubernetes liveness checks. I have some kubernetes daemonsets that don't do anything other than assert that things on the node are as they should, via grep exit status.