-
Notifications
You must be signed in to change notification settings - Fork 639
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
chore: script to automate updates of compatibility test configs for new releases #3541
Conversation
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.
Overall LGTM, nice work! I'm not so familiar with bash syntax so I just looked at it from a high level. This seems like a nice step in the right direction for automating maintenance of our compatibility tests
This tool should speed up adding/remove versions and reduce likelyhood of missing a file, but it'd still be nice to eventually autogenerate the matrix from a based on a base set of information. Just throwing the idea out there that a file like transfer-chain-a.json
should be the same for all release branch directories with the only difference being that older release branches don't test against newer version. This might be a good place to automate test generation next 🤔
cp -R "$directory_path"/* "$backup_dir" | ||
|
||
# Step 1: Replace the release version in JSON files | ||
echo "Enter the release version to replace (ie: v4.4.0, leave empty to skip):" |
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.
When do we do this?
Edit: I guess if we have a security issue, but then we'd need to have only a single living release branch for that major version?
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.
yes, if we have security issue. but i guess actually for this situation, the delete script is probably better than a replace script
done | ||
fi | ||
|
||
# Step 2: Add new release version to testing configuration files |
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.
Should we have a remove script as well?
1263b1b
to
365a24f
Compare
@@ -0,0 +1,101 @@ | |||
#!/usr/bin/python3 |
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.
Added an alternative in Python. Though bash does the trick, the script seemed like it was doing enough to warrant a language that doesn't make your eyes hurt.
I'm generally open to sticking with bash but find this solution both more readable, more maintainable and less error prone.
Still need to get some feedback from Carlos to make sure the script does what is typically required. Other than that, willing to drop this and go with bash if people prefer that.
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 definitely like the idea of this sort of tool existing as a python script instead of a bash one. It would be far easier to maintain.
9211f01
to
0296228
Compare
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.
Reviewing the python version, I really like the look of this script being in python. I think it would be a lot more maintainable (and even testable if we wanted to go to those lengths)
If we do go forward with the python version, I'd like to see type hints introduced since we'd be starting with a very small amount of code it would be easy to do.
@@ -0,0 +1,101 @@ | |||
#!/usr/bin/python3 |
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 definitely like the idea of this sort of tool existing as a python script instead of a bash one. It would be far easier to maintain.
def find_json_files(directory, ignores=(".",)): | ||
""" Find JSON files in a directory. By default, ignore hidden directories.""" | ||
for root, dirs, files in os.walk(directory): | ||
dirs[:] = (d for d in dirs if not d.startswith(ignores)) |
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 used to this syntax, my guess is that the [:]' is creating a copy or new variable so as to not re-assign the variable
dirs` in the for loop. I think this is a little awkward and would be easier to understand if we just used a different variable
i.e.
filtered_dirs = (d for d in dirs if not d.startswith(ignores))
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.
totally ugly, agree there but this in-place assignment of the returned directories allows for skipping any filtered entries when topdown=True
. Alternative would be an iteration over the dirs and manual del
of the correct indices.
In general, ignores
was added based on the initial bash script considering a .backup
dir being present. Since I haven't added that in (thinking a git restore
could do the trick) this could also be removed).
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.
oh I see so we're actually modifying the dirs that we're already iterating over
dirs[:] = (d for d in dirs if not d.startswith(ignores)) | ||
for file_ in files: | ||
if file_.endswith(".json"): | ||
yield os.path.join(root, file_) |
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.
love the generator usage 👍
|
||
def has_release_version(json_file, keys, version): | ||
""" Check if the json file has the version in question. """ | ||
return any(version in row for row in (json_file[key] for key in keys)) |
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 is just a personal preference, but I like keeping list comprehensions as shallow as possible. I find it can be difficult to read if you're not very experienced with python.
What about just
def has_release_version(json_file, keys, version):
""" Check if the json file has the version in question. """
values = (json_file[key] for key in keys)
return any(version in row for row in values)
the flattening in the any(version in row for row in values)
is not necessarily intuitive at first.
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.
but don't you know that one-liners always win? Will split up, serves no real point.
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.
one liners win until someone else needs to modify it 😄
for row in (json_file[key] for key in keys): | ||
if recent not in row: | ||
continue | ||
if op == "add": |
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.
maybe these can be constants? OP_ADD
, OP_REMOVE
etc.
""" Check if the json file has the version in question. """ | ||
return any(version in row for row in (json_file[key] for key in keys)) | ||
|
||
def update_version(json_file, keys, args): |
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.
technically handled in the parse args, code, but maybe we can raise a ValueError
if the operation is unknown in this function too just to be safe and explode when bad inputs are used.
require_version(args) | ||
return args | ||
|
||
def main(args): |
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.
one thing I noticed was that when we run the script giving an version that doesn't exists, it executes successfully but is just silent. I think it would be no harm either logging that the version wasn't found, or raise a ValueError with the input not having been found.
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.
yeah, can see the value in that
# Toggle if required. Indent = 4 matches jq. | ||
DUMP_ARGS = {"indent": 4, "sort_keys": False, "ensure_ascii": False} | ||
DUMP_ARGS: Dict[Any, Any] = { |
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.
unfortunate but mypy
(the type checker for the uninitiated) throws a big hissy-fit here. Typing **kwargs
in general are a pain iirc.
- Make script executable - Search in $PATH for bash - Exit on uninitialized vars, non-zero exit status in pipelines - Order the releases - Pretty print output.
5eb664e
to
9a0f611
Compare
1310304
to
9708c41
Compare
9708c41
to
52639b2
Compare
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.
LGTM thank you so much @charleenfei & @DimitrisJim , this will make the release process a lot simpler 🥇
One final nit, compat.py
is a bit ambiguous, maybe we could name the file update_compatibility_tests.py
to be more explicit, not a blocker at all though.
scripts/compat.py
Outdated
# Suggestions for recent and new versions. | ||
SUGGESTION: str = "for example, v4.3.0 or 4.3.0" | ||
# Supported Operations. | ||
Operation = enum.Enum("Operation", ["ADD", "REMOVE", "REPLACE"]) |
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.
❤️
|
||
def sorter(key: str) -> str: | ||
"""Since 'main' < 'vX.X.X' and we want to have 'main' as the first entry | ||
in the list, we return a version that is considerably large. If ibc-go |
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.
tysm for making a much more readable/maintainable version of my hack <3
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.
Awesome stuff! The python code looks pretty clean, its been a while since I looked at any! I think its more maintainable than bash.
LGTM 🚀
def sorter(key: str) -> str: | ||
"""Since 'main' < 'vX.X.X' and we want to have 'main' as the first entry | ||
in the list, we return a version that is considerably large. If ibc-go | ||
reaches this version I'll wear my dunce hat and go sit in the corner. |
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 will also eat my shorts on live stream
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.
At our current pace of 3 major releases a year we can get there in 33330 years. Think about the poor person on whose face this time bomb will explode, man.
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.
a quantum commit in the year 35353 "F*** you, DimitrisJim."
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.
Awesome work, @DimitrisJim! Great idea and initial implementation, @charleenfei!
def sorter(key: str) -> str: | ||
"""Since 'main' < 'vX.X.X' and we want to have 'main' as the first entry | ||
in the list, we return a version that is considerably large. If ibc-go | ||
reaches this version I'll wear my dunce hat and go sit in the corner. |
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.
At our current pace of 3 major releases a year we can get there in 33330 years. Think about the poor person on whose face this time bomb will explode, man.
Description
Currently, we have had to manually replace release versions with new ones if there is EOL or a security issue with one of the versions, and new releases necessitated the manual insertion of the release version into each compatibility text matrix config file.
This script automates each one of these paths depending on user input. It also creates a backup directory before any of the automations are run in case of something going wrong.
Commit Message / Changelog Entry
see the guidelines for commit messages. (view raw markdown for examples)
Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.
docs/
) or specification (x/<module>/spec/
).godoc
comments.Files changed
in the Github PR explorer.Codecov Report
in the comment section below once CI passes.