-
-
Notifications
You must be signed in to change notification settings - Fork 127
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
refactor in preparation for supporting other VCSs #217
Conversation
Split main.py into modules to (mostly) isolate the GitHub-specific code from the general TODO detection and program logic. This is both for readability/maintainability and to prepare for potentially supporting other version control systems (e.g. GitLab, BitBucket).
This is just a safe fallback for local testing. If environment variables which activate the creation of the GitHub client aren't set, then the Local client is created. It acts on the most recent commit of the repo in the working directory. Minor edit to GitHubClient so that it raises an EnvironmentError exception if INPUT_GITHUB_URL environment variable is not defined. This allows main to detect the error and fall back to trying to use the Local client
Add a new method, get_issue_url(), which returns the VCS-specific web URL for viewing an issue. This results in moving GitHub-specific code from main into GitHubClient, but with no change in behavior.
if not self.github_url: | ||
raise EnvironmentError |
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.
Error out early if GitHub-specific environment variable is not set. The exception is caught in main
, where it used to fall back to other options.
self.repo = os.getenv('INPUT_REPO') | ||
self.before = os.getenv('INPUT_BEFORE') | ||
self.sha = os.getenv('INPUT_SHA') | ||
self.commits = json.loads(os.getenv('INPUT_COMMITS')) or [] |
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.
Just FYI, but I found that this line raises the following TypeError
when INPUT_COMMITS
is undefined.
TypeError: the JSON object must be str, bytes or bytearray, not NoneType
I didn't want to rely on that error path though, which is why I added the segment above at lines 12-13.
Since it's not relevant to this PR, I didn't include the fix. But if you want to clean this up, this does what you were maybe intending to do:
self.commits = json.loads(os.getenv('INPUT_COMMITS', str([])))
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.
Never noticed that before, thanks! Yes, we should incorporate this.
def get_issue_url(self, new_issue_number): | ||
return f'Issue URL: {self.line_base_url}{self.repo}/issues/{new_issue_number}' |
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.
The syntax of this URL is different between GitHub and GitLab, so I pulled into the class (as a new method) rather than leaving it in main
.
# Try to create a basic client for communicating with the remote version control server, automatically initialised with environment variables. | ||
try: | ||
# try to build a GitHub client | ||
client = GitHubClient() | ||
except EnvironmentError: | ||
# don't immediately give up | ||
client = None | ||
# if needed, fall back to using a local client for testing | ||
client = client or LocalClient() | ||
|
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.
Rather than unconditionally trying to create a GitHub client (and failing with an ugly uncaught exception when you can't), this now catches the situation where the GitHub client can't be constructed and falls back to using a (very simply) Local client.
@@ -990,7 +102,7 @@ def _should_ignore(self, file): | |||
# Duplicate the line to retain the comment syntax. | |||
new_line = file_lines[line_number] | |||
remove = fr'{raw_issue.identifier}.*{raw_issue.title}' | |||
insert = f'Issue URL: {client.line_base_url}{client.repo}/issues/{new_issue_number}' | |||
insert = client.get_issue_url(new_issue_number) |
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.
As noted in my earlier comment, this is just to pull the GitHub-specific URL format out of this function. Each client is now responsible for implementing this method as appropriate for their system.
Great idea, thanks very much for the work! I'll have a quick scan over things but it all seems good to me. We'll probably need to update the tests as well, specifically: |
I was surprised, but that still works as is. I think it's because main already pulls everything else in. That said, it's probably better to be explicit about things and do the imports in the test file. On a related note, I found that running If you'd like me to share logs, just say the word. |
I think there are one or more issues depending on what the current working directory is set to, specifically with the
|
Yeah, I thought that could be the case, but I'm not sure it is. My current working directory is the clone root (the one containing Anyway, that's kind of a tangential conversation that is probably outside of the scope of this PR. If you do want to continue this conversation though (and I'm happy to do so), maybe it belongs over in Discussions? Since the tests are still passing for me when I run them one-by-one, I don't want to derail this PR over this unittest issue. |
I figured out the problem with the unittest. You were on the right track about the I've already got the fix in place. Do you want me to include it in this PR, or should I want until this PR is merged since the unittest issue is its own thing. Let me know. Thanks. |
Oh great. Yeah, let's sort it separately to keep things on track. So back to the original PR, everything looks good, I'm just going to test a few things and make sure it's all running smoothly, but seems fine from here. |
All seems great, just a few imports that can be cleaned up but that's it. Do you want to do that then I'll merge? Thanks! 😄 |
I'm happy to do it, but I'm not sure what you're asking for. If you've already done it locally, then feel free to push the changes you're talking about. Otherwise, just let me know exactly what needs done and I'll make the change. |
I think there were just a few unused imports in some of the files; (from memory) |
Done!
|
Thanks! Just removed a few more that I noticed. |
Yeah, I see that. It's interesting that BTW, I've just submitted the other PR we discussed to address the unittest issue. |
Sorry to say it, but the change in |
Huh. The tests ran fine but must not have picked up this issue. Thanks for sorting it. |
I think the problem is that the tests are currently just exercising I recognize it could be a bit of a big lift to put in tests for all of that, but maybe a quick middle ground is to use |
Sounds good; improving the tests is something I've been hoping to do. If you have any ideas or time to spare to look into it by all means. |
It's important to start off by saying that this PR shouldn't produce any behavioral changes. It just splits the various classes defined in
main.py
into their own modules. So why make the change?This is in preparation for future PRs to support other version control systems (VCS). In particular, I'm interested in supporting GitLab, but I don't see why this couldn't be extended to others, such as BitBucket/Jira. In fact, I've already adapted this project to support GitLab and have started using it on a self-hosted instance. I don't yet have feature parity so it's not ready to be merged though. But I wanted to go ahead and try to get this refactor worked in ASAP to ensure that our codebases don't drift too far.
Besides splitting the classes off, there are just a couple of minor changes being made here. Namely, I've added a
LocalClient
class. I found this to be helpful for local testing and it demonstrates how we can have a generic*Client
interface that is implemented as needed for GitHub, GitLab, etc. I've also tweaked the GitHub client constructor to make it easier to fall back to other clients in the future.In the few places where the code is not a straight copy of what was originally in
main.py
, I'll note it with inline comments.Thanks for this great project. I look forward to hopefully being able to make it even better!