Showing posts with label github. Show all posts
Showing posts with label github. Show all posts

Monday, December 30, 2024

Repo Deleter: A utility to batch-delete repositories from GitHub organizations

TL;DR: I created a tool to help batch-delete repositories from GitHub organizations. You can find the source repository at https://github.com/doctor-g/repo-deleter-flutter.

I have a few GitHub organizations that I re-use every semester. I set them up as through an academic account years ago. At the start of the semester, I add all my current students, and they push their work to repositories within this organization. This way, not only can I easily access students' work, they can also help each other out. For example, we can do peer code reviews in class across organizations without requiring anyone to use public repositories. I can also share all my sample code for the semester in the organization, and only those in the organization can get to it.

The downside to this approach is that the organizations require significant cleanup after a semester ends. Although I always instruct students how to move their work from the class organization into their own accounts, there are inevitably dozens of repositories left unattended. Deleting repositories manually through GitHub's web interface is mindless and tedious. There are a few online tools that claim to support batch-deletion of repositories, but I never had great luck with them.

After selecting a repository, going to its settings, scrolling to the bottom, selecting the delete option, and confirming that you want to delete the repository, then you also get to type in its name for super extra confirmation. Doing it once is not bad. Doing it fifty times is awful.

To make my life a little easier, two years ago, I created a little command-line tool to manage the process. I created it in Dart using the github package, which wraps GitHub's Web API. This little tool required you to go into the source code to modify the organization name and any special rules about which repositories to list. For example, I have had semesters where students had to name their projects in a pattern "PX-username" where X is the project number and username is a BSU username. The tool then had two different paths, which I would comment out alternately: the first printed the names of the repositories that it would delete, and the other would delete those repositories. It was not a great utility, and it needed manual cleanup for the repositories that didn't follow the patterns, but it did save me some manual work on GitHub's Web interface.

After a couple of semesters of dealing with that tool, I decided it was time to make something better, and so today I released Repo Deleter at https://github.com/doctor-g/repo-deleter-flutter. This new version includes a graphical user-interface powered by Flutter. Like its predecessor, it requires using a GitHub personal access token with the appropriate permissions; the details for this are given in the project README file. With the proper credentials in place, Repo Deleter allows you to select one of your GitHub organizations. Then it shows you all of the organization's repositories, both public and private. The user can select any number of these, and then, with the click of a button, delete them.

Repo Deleter screenshot (student names blurred out)

In addition to solving a proximal problem, there are two technical aspects to this project that I found rewarding. The first and most important one is that this application uses the bloc pattern. I mentioned my experiments with bloc as part of my tinkering with Dart and Flutter for creating tabletop-inspired videogames. That work is hidden away in a handful of private repositories, and because nothing became of them, it was hard to assess my own understanding of the pattern. I used bloc for the Repo Deleter as well, and it felt quite comfortable. I wonder how a bloc expert would critique the particular states and events that I used, but as a proof of concept, it definitely works. I suppose the proof of the pudding may be in six months when I have to open the project again and inevitably want to add a feature or two. Will I be able to read and make sense out of the code? Time will tell.

The less important but still interest aspect of Repo Deleter is that it's the first place where I used a formal logging framework in Flutter. It is not fancy: it's just the stock logging package, and I'm only echoing logs to a print command. Still, it eliminates the compiler warnings I had from the handful of print statements I had peppered in as ad hoc debugging aids.

One thing I would like to have done, but did not, was to have developed it via TDD. My early prototypes used the github package libraries throughout the application, with no adapter layers. Isolating the data layer from the logic layer would have facilitated testing layers without making actual network requests. I had idle hopes of using this as an example for my students, but in the end, I made the decision to just build on a working prototype rather than engineer something more robust.

Right now, the repository only has Linux platform support, but its easy enough to add more using the Flutter tools. I simply run it from Android Studio because it's easy to set an environment variable for a specific run configuration.

Tuesday, August 30, 2022

CS315 Game programming project report failure and recovery

A few weeks ago, I wrote about how I removed a cyclic dependency from my CS315 class by moving the project report from a git repository to a GitHub wiki. This solution was clear, simple, and wrong. It turns out that GitHub wikis are only available to public repositories when using GitHub Free. Over the weekend, a student working on the first project reached out to me, pointing out that the wiki feature didn't seem to be available. I confirmed the problem and set about seeking a new solution.

After some consideration, I decided the simplest solution was to remove the checklist item that says that a student has submitted their work on time. This item was the crux of the problem, since it forced someone to either leave it unchecked at the time of submission or to check it prematurely. I did not want to change actual course policy, however, so I had to add a general clause stating that work has to be turned in by the deadline to receive credit. This is a little less elegant, since now a student's grade is determined by a combination of checklist items and a general policy. However, it's a familiar kind of policy, and so I hope students don't mind the inconsistency.

It turns out, this is actually a change in policy, although I didn't think about it until writing this blog post. Previously, someone could use a Save Point to resubmit work that was late, since the deadline itself was in the checklist. Now that it is not in the checklist, the course plan gives students no option to earn credit for submitting late work. This was not quite my intention, since the whole idea of having a Save Point is to deal with unforeseen circumstances, and such circumstances do sometimes lead to the inability to submit work on time. I suppose I better get back to editing the course plan to add another general rule, that Save Points can additionally be used to submit work late. That is even more inconsistent and inelegant, but I have not found another approach to fill the bill.

Incidentally, the first "easy" solution I came up with was to have students just submit two things on Canvas: a link to their repository and a separate project report. Unfortunately, Canvas does not seem to support this. Even though the teacher's interface makes it look like you can require a student to submit both items, what students see is that they can only submit one or the other.

Monday, July 11, 2022

A quick and dangerous tool for bulk deletion of GitHub repositories from within an organization

I use GitHub for almost all of my classes, and each class has its own named organization. Students and teams submit work through GitHub, which means that there are a lot of repositories built up in the organization by the end of the semester. I always tell my students to make their own copies or forks and then to clean their work out of the GitHub organization, but very few actually do this. Because I reuse the organizations, this leaves it up to me to clean out the repositories between semesters.

Deleting repositories by hand is tedious. For reasons I cannot explain, Repo Remover only shows a small subset of the repositories in the organization, and Repo Sweeper shows none. This morning, after taking out a few with Repo Remover, I started the process of removing repositories one at a time. Two thoughts crossed my mind: "Automate tedious manual work" and "Don't spend more time writing a program than you will save doing it by hand." Well, since I have to do this between every semester, I decided I had had enough tedium.

I've been quietly working on a Summer project using Flutter, and so after confirming that there's a nice library to wrap GitHub's API, I decided to see if I could whip something up in Dart. My major stumbling block was not realizing that a variable exported within Android Studio's terminal would not be available in the execution environment of the IDE. Once I specified my personal access token in the run configuration instead, everything worked like a charm. There's really hardly any code to it, and I've released it under GPL on GitHub at https://github.com/doctor-g/repo_deleter.

The code obviously would need to be modified for others' purposes. Right now, the "bsu-cs315" organization is hard-coded, and there's no UX to speak of. It just deletes all the repositories that start with the letter "P". Of course, I didn't start with that code. I started by having it print all the organization repositories, then I filtered out those I didn't want, and then I changed my print statement to a deletion.

Hopefully this will save me headaches next time I need to clean out an organization. Also, hopefully by writing this blog post, I will remember that I wrote a tool to make my life a little easier.

Tuesday, November 2, 2021

Using KayKit Animations in Godot Engine

I recently learned about Kay Lousberg's CC0 KayKit asset packs, and I thought it might be fun to try to bring them into Godot for consideration in a NaGaDeMon project. However, I ran into trouble following the recommended approach a few days ago. Today, I was able to figure out the missing pieces. All the steps and a sample project are given in a repository I just put up on GitHub.



Thursday, July 9, 2020

Deploying Godot Engine Web Games to GitHub Pages with Continuous Integration

UPDATE: This post presents what I consider a slightly easier approach.

After figuring out how to use continuous integration with Flutter Web apps on GitHub Pages, I turned my attention to Godot Engine. Through my FamJam projects, I have developed a pair of scripts (build.sh and deploy.sh
) for building and deploying games to GitHub Pages. It seemed like a natural extension to see if I could do this automatically. This could be useful both for my Fam Jams and, of course, for my revised game programming course.

In addition to GitHub actions, the other two critical pieces to getting this to work are aBARICHELLO's Godot CI Docker image and, as used in my Flutter approach, peaceiris' GitHub Pages Action. Here is the simple version:

My custom build script usse NatrimCZ's approach of reducing project download size by zipping the project files and extracting them client-side, and it was surprisingly straightforward to incorporate that into an alternative GitHub workflow:

Either approach, just like with Flutter, requires you to have an authoritative push to gh-pages before using GITHUB_TOKEN for authentication will work; once again, you can do something like this to get that done:

git push origin master:gh-pages
Also, as mentioned in the comments, the script assumes that you have already configured the project with HTML5 export and that you have set the export location to build/web.

Wednesday, July 8, 2020

Deploying Flutter Web apps to GitHub Pages

UPDATE: This post presents what I consider a slightly easier approach.

I spent most of the day trying to find the easiest way for my students to publish Flutter Web apps to GitHub Pages. My quest started at zonble's Medium post, proceeded with my taking a closer look at GitHub's workflow and actions documentation, and finally tripping across the handy GitHub Pages action. After a bunch of testing, I'm feeling confident about my approach, which I will explain below.

The essence of the approach is to use a custom workflow by placing the following file in your project in the path .github/workflows/workflow.yml. Then, whenever you push to master, the workflow will be triggered and your built application will be deployed to GitHub Pages.

This approach is susceptible to the known problem with first GitHub Pages deployments using GITHUB_TOKEN. The problem can be entirely avoided by creating and then specifying a personal access token for the repository. However, I think a simpler approach—that also requires fewer tokens cluttering up the configuration—is to do one manual push to gh-pages, after which the simpler workflow will work as expected. My suggestion is, before pushing to the master branch on GitHub, push your local copy to the remote gh-pages branch, as shown below.

git push origin master:gh-pages

That's enough for GitHub to recognize that you will be deploying to that branch. Follow that up with a push to the remote master branch as usual, and you should be all set.