As developers, we've all been there. A new release is ready to ship, and someone needs to compile the release notes. This usually involves using the GitHub Release Notes feature, or tediously assembling a document manually. Sure, pressing that button is easy. But it's not always accurate, and it lacks additional features. And manually doing it? That's a pain, and it's easy to miss something.
Something new
Working with JMac, creator of Laravel Shift, we set out to build a tool that would make this process smoother. The result is release.new - a Laravel application made with Livewire that generates release notes from your Git history with just a few clicks.
Our process
The process of building release.new was a fun journey and we learned a lot along the way, and I'm excited to share some of the details with you, and the lessons we learned in this series.
Most of the features Jason and I worked on were done in pairing sessions. This was quite new to me, but I quickly learned to appreciate the benefits of pairing. It meant we both knew how the code worked, and we could combine our expertise to build the best thing possible.
We also did some asynchronous work in between, or when one of us was on vacation. While Jason mainly handled the Git operations and background processing, I focused on the Livewire components and the natural language processing and release notes assembly. Then we paired to integrate everything together, and make improvements to the user experience.
Our architecture
At its core, release.new follows these steps:
- A modal form that takes the repository details and version range
- A fast bare Git clone of the repository that runs in the background using Horizon
- Parse, analyze, and categorize commits using keyword matching and natural language processing
- Generate value and printer objects to manage data with object oriented techniques
- Present a reactive preview that is entangled to the Livewire form options
In this series we'll dive deep into each of these steps, and more. But first, let's take a high level look at the architecture to give you some background information.
Form modal and prefetching
The first step is a modal form that takes the repository details and version range so we know where to get the Git history from. As soon as we have the repository details, we fire off a background job to prefetch the Git history, this makes the process feel feel faster for the user, as we buy some time while the user fills in the rest of the form.
Parallel background processing
The biggest problem we had was speed, something Jason dove deep into in his blog post Optimizing Git Commit History. Each step we needed to make could take a few seconds, which all compounded together into a noticeably slow experience.
To speed things up, we in addition to prefetching run most jobs in parallel. Thankfully Laravel and Horizon make this a breeze! I really recommend checking out Jason's post to learn more about the optimizations we made.
Reactive preview
Once all the data was generated on the backend, one of the most important aspects was providing instant feedback that modifies the output as the user changes options.
We do this by entangling the Livewire form with the output preview, and binding the options to the printer object that generates the output based on the form option values. This gives users immediate feedback as they adjust options, making it easy to fine-tune the output.
The object-oriented printer class lets us build the output in a fluent and declarative way on the backend. This approach makes it easy to extend with new features in the future, and is easily testable.
Smart categorization
The heart of release.new is its ability to intelligently categorize changes. We analyze commit messages and contents to sort changes into categories like "Added", "Changed", "Fixed" using keyword matching and natural language processing.
This is done in one of those parallel background jobs I mentioned earlier. Then the printer uses that data in assembling the release notes. This approach is used in several places and decouples the analysis from the formatting, with the benefit of making the code more modular and maintainable.
Testing for reliability
Given the complexity of Git operations and Markdown generation, we put a lot of effort into testing. For many features and fixes we used a test-driven approach to ensure we were building the right thing according to the requirements we set out to meet and our design specifications.
What's next?
This is just the beginning of our journey with release.new. We're continuously improving the tool based on user feedback and our own experiences. Some areas we're exploring:
- Custom formatting templates
- Ability to publish releases to GitHub
- More Git providers, and private repositories
Thanks for reading! In the next post, we'll dive deeper into how we built the reactive preview that entangles the Livewire form with the output. In the meantime, why not share this post and release.new if you enjoyed it?