{"id":22827,"date":"2024-03-29T16:17:57","date_gmt":"2024-03-29T15:17:57","guid":{"rendered":"https:\/\/daniel.haxx.se\/blog\/?p=22827"},"modified":"2024-03-29T16:26:22","modified_gmt":"2024-03-29T15:26:22","slug":"10000-bugfixes-in-10000-days","status":"publish","type":"post","link":"https:\/\/daniel.haxx.se\/blog\/2024\/03\/29\/10000-bugfixes-in-10000-days\/","title":{"rendered":"10,000 bugfixes in 10,000 days"},"content":{"rendered":"\n<p>We keep track of bugfixes done to curl. All bugfixes ever done. A while back I also went back and populated the lists with details from all the releases to the pre-cursors of curl: httpget and urlget. All and every change made since November 1996.<\/p>\n\n\n\n<p>The bugfixes are all listed on the <a href=\"https:\/\/curl.se\/changes.html\">curl changelog page<\/a>. The bugfix counter can be found on <a href=\"https:\/\/curl.se\/docs\/releases.html\">the release log<\/a> page.<\/p>\n\n\n\n<p>The rate of bugfixes has been increasing over the years. I think in terms of actual bugs being squashed and fixes being merged, but also partly because we have gotten much better at keeping meticulous logs and do better release notes.<\/p>\n\n\n\n<p>A bugfix can be a single letter typo fix in a document, a spell-fix in a source code comment or it can fix a serious security vulnerability. From high to low, from important to a small subtle detail. The counter does not value, it is just a counter.<\/p>\n\n\n\n<p>When  we shipped the recent curl version, 8.6.0, the counter said 9,888 shipped bugfixes. The other day, when <a href=\"https:\/\/daniel.haxx.se\/blog\/2024\/03\/27\/curl-8-7-0\/\" data-type=\"post\" data-id=\"24390\">8.7.0 and 8.7.1<\/a> shipped, the counter was upped to surpass 10,000 and now says: <strong>10,051<\/strong>.<\/p>\n\n\n\n<p>These bugfixes happened thanks to <strong>3,134<\/strong> contributors, out of which <strong>1,252<\/strong> persons have authored commits merged into the curl source repository.<\/p>\n\n\n\n<p>This journey started with httpget. The first ever release of httpget 0.1 that was made public happened on November 11 1996. Today, that is exactly <strong>10,000<\/strong> days ago.<\/p>\n\n\n\n<p>We only have git commits stored from late 1999, but that counter is almost at 32,000 now. Making a little less than every third commit ever done a logged bugfix.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69da5bfca5558&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69da5bfca5558\" class=\"aligncenter size-full wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2469\" height=\"1389\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2024\/03\/Screenshot-2024-03-28-at-13-21-16-curl-Project-status-dashboard.png\" alt=\"\" class=\"wp-image-24423\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Number of bugfixes and bugfix rate over time in the curl project.<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">How I do the release notes<\/h2>\n\n\n\n<p>This is highly scripted task.<\/p>\n\n\n\n<p>It starts with: every commit of the <strong><code>RELEASE-NOTES<\/code><\/strong> file in git that makes it up-to-date needs to use the single word &#8220;synced&#8221; as commit message. The commit that syncs it.<\/p>\n\n\n\n<p>Further, I have an alias in my <strong><code>~\/.gitconfig<\/code><\/strong> file that says:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[alias]\n  latest = log @^{\/RELEASE-NOTES:.synced}..<\/pre>\n\n\n\n<p>This allows me to invoke <strong><code>git latest<\/code><\/strong> to get a list of the latest changes done in the repository since I most recently synced the <code>RELEASE-NOTES<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sync<\/h2>\n\n\n\n<p>When that list starts to grow, typically roughly every four to ten days something, I invoke the <strong><code>release-notes.pl<\/code><\/strong> script we have in the curl git repository. This scripts gets all the changes since the most previous sync and inserts them into the RELEASE-NOTES file, complete with a correct reference to the associated GitHub issue or pull-request.<\/p>\n\n\n\n<p>The actual bullet point text it inserts comes from the first line of the corresponding commit message. The links comes from parsing commit messages and finding keywords and links according to how the project dictates how they should be used. This is one reason why it is important to do good commit messages following the correct style in the project. It makes the release notes job easier and the results better.<\/p>\n\n\n\n<p>The script does not know what&#8217;s a change, what&#8217;s a bugfix or what&#8217;s not even worthy of mentioning. It just adds all changes to top the list of changes (and includes a convenient separator so that it is easy to spot the newly added ones) and the next step for me is then to manually go over the list and delete the ones that aren&#8217;t intended to be mentioned there and move the few changes into the correct section of the release notes.<\/p>\n\n\n\n<p>I run <strong><code>release-notes.pl cleanup<\/code><\/strong> which then sorts the lists alphabetically and removes dangling references (which are leftovers from the lines I removed).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Contributors<\/h2>\n\n\n\n<p>We keep track, try to say thanks to and give credit to every contributor that helps out in the project. No matter the size of the contribution. When someone has reported a bug. the reporter is credited in the commit message of the bugfix. We also give credit to co-authors and people assisting in solving the issues etc. To make sure we mention and give credit to the contributors and keep track of them beyond what git itself does.<\/p>\n\n\n\n<p>We can also add names manually to the release notes file, like if we had forgotten to mention them in a commit message. Then I run the <strong><code>contributors.sh<\/code><\/strong> script. It reads the list of names currently in the RELEASE-NOTES and then scans all the git changes since the previous sync and generates an updated list of all git authors, committers and everyone else who are credited, and it outputs an updated list (and contributor counter). That updated list is then pasted into RELEASE-NOTES.<\/p>\n\n\n\n<p>In recent years, in a normal eight week release cycle, we typically feature 60 to 80 named contributors in this file. Of course, top contributors in the project tend to get mentioned in just about every release notes file, as they just have to help out and contribute once every 56 days to appear there.<\/p>\n\n\n\n<p>On release days, we update the <strong><code>docs\/THANKS<\/code><\/strong> file (using the <strong><code>contrithanks.sh<\/code><\/strong> script) where all contributors who ever helped out are mentioned and saved for the future.  That list of people is also made visible on <a href=\"https:\/\/curl.se\/docs\/thanks.html\">the thanks page<\/a> on the curl website.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Counters<\/h2>\n\n\n\n<p>At the top of the release notes we have a few counters displayed. It looks similar to:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Public curl releases:         255\nCommand line options:         258\ncurl_easy_setopt() options:   304\nPublic functions in libcurl:  93\nContributors:                 3119<\/pre>\n\n\n\n<p>After the list of contributors have been pasted into the current release notes, I invoke the <strong><code>delta<\/code><\/strong> script, which shows a lot of curl git repository statistics since the most previous release tag. That input includes the numbers shown in the release notes top, so if they are different now I update the release notes accordingly with the updated data. Most frequently, the contributor counter has been bumped.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Commit<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>included the lists of bugfixes and changes<\/li>\n\n\n\n<li>updated contributors<\/li>\n\n\n\n<li>updated the counters<\/li>\n<\/ul>\n\n\n\n<p>The <strong><code>RELEASE-NOTES<\/code><\/strong> file is then committed to git using &#8220;synced&#8221; as commit message. Until it is time to sync it again.<\/p>\n\n\n\n<p>Because of this work, we can offer <a href=\"https:\/\/curl.se\/dev\/release-notes.html\">the pending release notes<\/a> on the website, as it is the work in progress file with the changes we have already logged that is targeted to be included in the next release.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Release<\/h2>\n\n\n\n<p>Of course, on release days I make sure to do a final update so that all the last changes get into the file before release as then the file ends up in the release tarball, that is locked, signed and stored the archives.<\/p>\n\n\n\n<p>After a release, I just manually erase the lists from the file and clear the list of names and commit. Then we start rebuilding it again with new stuff in the new release cycle.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We keep track of bugfixes done to curl. All bugfixes ever done. A while back I also went back and populated the lists with details from all the releases to the pre-cursors of curl: httpget and urlget. All and every change made since November 1996. The bugfixes are all listed on the curl changelog page. &hellip; <a href=\"https:\/\/daniel.haxx.se\/blog\/2024\/03\/29\/10000-bugfixes-in-10000-days\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">10,000 bugfixes in 10,000 days<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":5,"featured_media":10394,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[123,33],"class_list":["post-22827","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-curl","tag-bugfixes","tag-curl-and-libcurl"],"_links":{"self":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/22827","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/comments?post=22827"}],"version-history":[{"count":41,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/22827\/revisions"}],"predecessor-version":[{"id":24433,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/22827\/revisions\/24433"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media\/10394"}],"wp:attachment":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media?parent=22827"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/categories?post=22827"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/tags?post=22827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}