Site Overlay

Finished my GitHub CLI tool

I never intended this to be a full fleshed CLI tool comparable to the likes of the real GitHub CLI. This was simply a way to refresh myself and have fun. I have accomplished this, and am now calling this “Feature Complete”. You can play around with it yourself from the repository on gitlab.


Today I learned some fun things with httpx mainly. The main thing I focused on today was figuring out pagination. The GitHub API uses the link header which I had never seen before.

The format of the header is a url, and then a relationship of that url. Lets take my friend Andrey’s repos for example:

{'link': '<>; rel="next", <>; rel="last"', ...}

sample header value from Getting Andrey’s repositories list and checking pagination

The link header there has two items split by a comma, each with two fields split by a semicolon, the first of which is a URL inside angle brackets… and AGHH this is going to be annoying to parse! Luckily httpx responses have this handled and client.get(...).links returns a lovely dictionary of the proper data.

With a response.links.get('next') check, you can get the url from response.links['next']['url']. So much nicer than writing some regular expressions.


With that accomplished, I then added pytest-cov to my and was able to leverage some coverage checks. I was about 30% with the latest changes (much higher than anticipated!) so I knew what I wanted to focus on next. The API seemed the easiest to test first again, so I changed around how I loaded my fixtures and made it pass in a name and open that file instead. In real code I would not have the function in both my test files, I would refactor it, but again, this is just a refresher, I’m lazy.

I decided earlier that I also wanted to catch HTTP 403 errors as I ran into a rate limit issue. Which, I assure you dear reader, was a thousand percent intentional so I would know what happens. Yeah, we’ll go with that.

Py.Test has a context manager called pytest.raises and I was able to just with pytest.raises(httpx.HttpStatusError) and check that raise really easily.

The next bits of testing for the API were around the pagination, I faked two responses and needed to update my link header, checking the cases where there was NO link, was multiple pages, and with my shortcut return – in case the response was an object not a list. Pretty straight forward.

The GHub file tests were kind of annoying, I’m leveraging rich.table.Table so I haven’t been able to find a nice “this will make a string for you” without just using rich‘s print function. I decided the easiest check was to see if the Table.Columns.Cells matched what I wanted, which felt a little off but it’s fine.

The way I generated the table is by making a generator in a pretty ugly way and having a bunch of repo['column'], repo['column'] responses, rather than doing a dict comprehension and narrowing the keys down. If I ever come back to this, I MIGHT reassess that with a {k:v for k,v in repos if k in SELECTED_KEYS} and then yield a dictionary, but it’s not worth the effort.

Overall I’d say this project was fun. It gave me a glimpse back into the Python world, and an excuse to write a couple blog posts. My next project is to get a Django site up and running again, so I can figure out how to debug my django-dbfilestorage.

Closing Thoughts

If I had to do this again, I would probably have tried some test driven development. I’ve tried in the past, but I don’t work on a lot of greenfield projects. I tend to be the kind of engineer who jumps HEAD FIRST into code and then tests are an after thought.

I also kind of want to rewrite this in Go and Rust, two other languages I’ve been fond of lately, just to see how they’d compare in fun. I haven’t done any API calls with Rust yet, only made a little Roguelike by following Herbert Wolverson’s Hands-On-Rust book. The Tidelift CLI is all Go and a bazillion API calls (okay like ten) so that wouldn’t be too hard to use like SPF13’s Cobra CLI library and make a quick tool that way.

One fun thing I learned while moving things over to GitLab is that my user Tyrel is a super early adopter. I was in the first 36,000 people! I showed a screenshot of my user ID to my friend Sunanda at GitLab and we had fun finding that out.

Leave a Reply

Your email address will not be published. Required fields are marked *