[{"data":1,"prerenderedAt":929},["ShallowReactive",2],{"$B3SvcJdz-H":3,"pages-links":23,"posts-links":29,"posts-search":58,"blog-make-version":129,"decks-for-make-version":924,"meta":925},{"id":4,"title":5,"author":6,"description":14,"extension":15,"meta":16,"repository":17,"stem":21,"__hash__":22},"meta\u002Fmeta.yml","bmo.dev",{"name":7,"github":8,"gitlab":9,"email":10,"linkedin":11,"mastodon":12,"bio":13},"William Little","https:\u002F\u002Fgithub.com\u002Fbmodotdev\u002F","https:\u002F\u002Fgitlab.com\u002Fbmodotdev\u002F","L29hqTSwqROvoJ8hMTI2","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fwilliam-e-little-jr\u002F","https:\u002F\u002Fdefcon.social\u002F@bmodotdev","I am a Full Stack Software & DevOps Engineer who loves building and experimenting with Software, Linux, & electronics.\n","A personal blog where I share my thoughts, projects, and anything I might find interesting or helpful.\n","yml",{},{"url":18,"git":19,"branch":20},"https:\u002F\u002Fgitlab.com\u002Fbmodotdev\u002Fbmo.dev\u002F","git@gitlab.com:bmodotdev\u002Fbmo.dev.git","main","meta","MPtcc2KHfBCBy4V4SDhZFIvjyZ_Ba4e-yDnx_Ok_KOs",[24],{"path":25,"extension":26,"title":27,"id":28},"\u002Fabout","md","About","pages\u002Fabout.md",[30,34,38,42,46,50,54],{"path":31,"extension":26,"title":32,"id":33},"\u002Fblog\u002Fconventional-commit-caveats","Conventional Commit Caveats","blog\u002Fblog\u002Fconventional-commit-caveats.md",{"path":35,"extension":26,"title":36,"id":37},"\u002Fblog\u002Fdodging-a-critical-cve-with-zta","Dodging a Critical CVE with ZTA","blog\u002Fblog\u002Fdodging-a-critical-cve-with-zta.md",{"path":39,"extension":26,"title":40,"id":41},"\u002Fblog\u002Flog4perl-mixed-screen-appender","Mixed Output Streams with Log4perl Screen Appender","blog\u002Fblog\u002Flog4perl-mixed-screen-appender.md",{"path":43,"extension":26,"title":44,"id":45},"\u002Fblog\u002Fmake-version","make version","blog\u002Fblog\u002Fmake-version.md",{"path":47,"extension":26,"title":48,"id":49},"\u002Fblog\u002Fpadding-oracle-attacks-rubiks-cow","Padding Oracle Attacks & Rubik’s Cow","blog\u002Fblog\u002Fpadding-oracle-attacks-rubiks-cow.md",{"path":51,"extension":26,"title":52,"id":53},"\u002Fblog\u002Ftracing-signals-in-linux","Tracing Signals in Linux","blog\u002Fblog\u002Ftracing-signals-in-linux.md",{"path":55,"extension":26,"title":56,"id":57},"\u002Fblog\u002Fwhy-are-go-modules-in-my-nodes-modules","Why are Go modules in my node_modules?","blog\u002Fblog\u002Fwhy-are-go-modules-in-my-nodes-modules.md",[59,69,81,90,100,108,117],{"path":55,"title":56,"description":60,"tags":61,"thumbnail":64,"created":68},"Let’s dissect this developer pattern that leads to arbitrary code execution across languages.",[62,63],"go","js",{"sm":65,"md":66,"lg":67},"\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_sm.webp","\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_md.webp","\u002Fassets\u002Fdavid-mitchell-great-british-baking-show_lg.webp","2026-04-07",{"path":35,"title":36,"description":70,"tags":71,"thumbnail":76,"created":80},"Let’s discuss tenets of Zero Trust Architecture, Go, gRPC, and why everyone dodged CVE-2026-33186, right?",[72,73,62,74,75],"awk","cve","grpc","zta",{"sm":77,"md":78,"lg":79},"\u002Fassets\u002Fdodging-the-flyer_sm.webp","\u002Fassets\u002Fdodging-the-flyer_md.webp","\u002Fassets\u002Fdodging-the-flyer_lg.webp","2026-04-02",{"path":47,"title":48,"description":82,"tags":83,"thumbnail":85,"created":89},"In this thought experiment, you’ll learn about cryptographic primitives, combinitorical group theory, and along the way, gain a deeper appreciation for 1999’s film, The Matrix. Oh yeah, and a Cow!",[84],"cryptography",{"sm":86,"md":87,"lg":88},"\u002Fassets\u002Fbournemouth_sm.webp","\u002Fassets\u002Fbournemouth_md.webp","\u002Fassets\u002Fbournemouth_lg.webp","2026-03-06",{"path":43,"title":44,"description":91,"tags":92,"thumbnail":95,"created":99},"Here is how I went about implementing a simple versioning system for my Go project using Conventional Commmits, awk, and make.",[72,93,62,94],"git","semver",{"sm":96,"md":97,"lg":98},"\u002Fassets\u002Flego-pieces_sm.webp","\u002Fassets\u002Flego-pieces_md.webp","\u002Fassets\u002Flego-pieces_lg.webp","2025-11-11",{"path":31,"title":32,"description":101,"tags":102,"thumbnail":103,"created":107},"The Conventional Commmits spec aims to bring structure to commit messages so that we write succint yet meaningful commits. That sounds great, but let’s examine some potential drawbacks.",[93,94],{"sm":104,"md":105,"lg":106},"\u002Fassets\u002Fgit-commit_sm.webp","\u002Fassets\u002Fgit-commit_md.webp","\u002Fassets\u002Fgit-commit_lg.webp","2025-11-07",{"path":39,"title":40,"description":109,"tags":110,"thumbnail":112,"created":116},"Log4perl provides a powerful logging framework, but how can we dynamically and meaninfully use stdout and stderr?",[111],"perl",{"sm":113,"md":114,"lg":115},"\u002Fassets\u002Fperl-latte-onion_100x100.webp","\u002Fassets\u002Fperl-latte-onion_250x250.webp","\u002Fassets\u002Fperl-latte-onion_600x600.webp","2022-02-14",{"path":51,"title":52,"description":118,"tags":119,"thumbnail":124,"created":128},"Signals, or software interrupts, are used to communicate with a process. They could be used to kill a process, restart, or signal a segmentation fault, but how can we know where that signal came from?",[120,121,122,123],"signals","systemtap","strace","linux",{"sm":125,"md":126,"lg":127},"\u002Fassets\u002Ftraffic-light_sm.webp","\u002Fassets\u002Ftraffic-light_md.webp","\u002Fassets\u002Ftraffic-light_lg.webp","2022-02-13",{"id":45,"title":44,"body":130,"created":99,"description":91,"extension":26,"meta":918,"navigation":764,"path":43,"seo":919,"stem":920,"tags":921,"thumbnail":922,"updated":80,"__hash__":923},{"type":131,"value":132,"toc":910},"minimark",[133,158,163,174,183,186,198,209,212,216,229,246,282,284,287,598,605,608,611,626,629,632,900,904,907],[134,135,136,144],"with-caption",{},[137,138,139],"p",{},[140,141],"img",{"alt":142,"src":98,"target":143},"Photo by Xavi Cabrera","_blank",[145,146,148],"template",{"v-slot:caption":147},"",[137,149,150,151],{},"Photo by ",[152,153,157],"a",{"href":154,"rel":155,"target":143},"https:\u002F\u002Funsplash.com\u002Fphotos\u002Fyellow-red-blue-and-green-lego-blocks-kn-UmDZQDjM",[156],"nofollow","Xavi Cabrera",[159,160,162],"h2",{"id":161},"owning-your-version","Owning Your Version",[137,164,165,166,168,169,173],{},"Previously, I talked about ",[152,167,32],{"href":31},",\nbut it’s still my preferred style of writing git commits.\nSince it’s such a ",[170,171,172],"em",{},"lightweight"," specification, we can easily implement our own\nautomated version management system.",[137,175,176,177,182],{},"First, there are many implementations already out there; plugins for IDE’s and\nlinters, standalone scripts\u002Fbinaries, and CI\u002FCD templates to name a few.\nMany of which are likely more feature rich than what I will show here.\nIf you are implementing an automated version management system for a large\norganization across many types of projects, there may be projects that wish\nto make full use of the ",[152,178,181],{"href":179,"rel":180,"target":143},"https:\u002F\u002Fsemver.org\u002Fspec\u002Fv2.0.0.html",[156],"Semantic Version","\nspecification in ways you did not foresee.",[137,184,185],{},"Choosing an existing implementation with a large feature set may serve you best.\nHowever, I love that the simplicity of the specification allows us to write a\nsmall script that will cover majority of our use case, should be easily\nunderstood at a glance by most developers, empowers us to support types we want,\nand doesn’t require any 3rd-party dependencies that we might feel obligated to\nvet or inventory.",[137,187,188,191,192,197],{},[170,189,190],{},"Update:"," Socket.dev posted a report on Feb 20, 2026:\n",[152,193,196],{"href":194,"rel":195,"target":143},"https:\u002F\u002Fsocket.dev\u002Fblog\u002Fsandworm-mode-npm-worm-ai-toolchain-poisoning",[156],"SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains",":",[199,200,201,204],"block-quote",{"link":194},[137,202,203],{},"The Action also patches release toolchain configurations (.releaserc,\n.releaserc.json, .release-it.json, and variants) to inject\n@semantic-release\u002Fexec with prepareCmd: \"node -e \\\"try{require('CARRIER')}catch(e){}\\\"\".\nThis ensures every subsequent npm publish from the infected repo silently\nexecutes the carrier package, creating an additional propagation path\nthrough the release pipeline.",[145,205,206],{"v-slot:cite":147},[137,207,208],{},"Public GitHub Action: ci-quality\u002Fcode-quality-check",[137,210,211],{},"If you truly don’t need the entire Semantic Versioning specification,\ndon’t throw the kitchen-sink at it.",[159,213,215],{"id":214},"git-log","git log",[137,217,218,219,222,223,228],{},"We need to craft a ",[220,221,215],"code",{}," command that will make it easy to parse for\nConventional Commit specification; therefore, the important parts are the\nsubject and ",[152,224,227],{"href":225,"rel":226,"target":143},"https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit-interpret-trailers\u002F2.51.0",[156],"git trailers",".",[137,230,231,235,236,241,242,245],{},[152,232,215],{"href":233,"rel":234,"target":143},"https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit-log",[156]," allows us to\nspecify the exact format string, and even provides a\n",[152,237,240],{"href":238,"rel":239,"target":143},"https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit-log#Documentation\u002Fgit-log.txt-trailersoption",[156],"trailers placeholder","\nthat has options to limit the git trailer key we are looking for.\nThe default separator is a newline, so we specify a comma using format code\n“%x2c”.\nOf course, the default is to print in reverse chronological order, so we must\nalso specify ",[220,243,244],{},"--reverse"," to read our Conventional Commits chronologically.",[247,248,252],"pre",{"className":249,"code":250,"language":251,"meta":147,"style":147},"language-bash shiki shiki-themes houston","git log --reverse --no-merges \\\n  --pretty='format:%s %(trailers:key=BREAKING-CHANGE,separator=%x2C)'\n","bash",[220,253,254,276],{"__ignoreMap":147},[255,256,259,262,266,269,272],"span",{"class":257,"line":258},"line",1,[255,260,93],{"class":261},"stHQG",[255,263,265],{"class":264},"se2J0"," log",[255,267,268],{"class":264}," --reverse",[255,270,271],{"class":264}," --no-merges",[255,273,275],{"class":274},"sLo_3"," \\\n",[255,277,279],{"class":257,"line":278},2,[255,280,281],{"class":264},"  --pretty='format:%s %(trailers:key=BREAKING-CHANGE,separator=%x2C)'\n",[159,283,72],{"id":72},[137,285,286],{},"Below is an awk script that supports the git trailer key “BREAKING-CHANGE” and\na subject scope\u002Ftype appended with an exclamation.\nWe can also choose the exact types we want to support, along with which types\nshould increment our semantic version.",[247,288,290],{"className":249,"code":289,"language":251,"meta":147,"style":147},"#!\u002Fusr\u002Fbin\u002Fawk -f\nBEGIN { major = minor = patch = 0 }\n{\n  if ($0 ~ \u002FBREAKING-CHANGE:|^[^\\s:]+!:\u002F) {\n    major++; minor = patch = 0\n  } else if (tolower($0) ~ \u002F^(feat|build|ci|chore)[^\\s:]*:\u002F) {\n    minor++\n  } else if (tolower($0) ~ \u002F^fix[^\\s:]*:\u002F) {\n    patch++\n  } else if (tolower($0) !~ \u002F^(docs|style|refactor|test)[^\\s:]*:|fixup!\u002F) {\n    printf \"Invalid type: %s\\n\", $0 > \"\u002Fdev\u002Fstderr\"\n  }\n}\nEND { printf \"v%d.%d.%d\\n\", major, minor, patch }\n",[220,291,292,298,328,334,357,378,447,453,483,489,544,562,568,574],{"__ignoreMap":147},[255,293,294],{"class":257,"line":258},[255,295,297],{"class":296},"sy89t","#!\u002Fusr\u002Fbin\u002Fawk -f\n",[255,299,300,303,306,309,312,315,317,320,322,325],{"class":257,"line":278},[255,301,302],{"class":261},"BEGIN",[255,304,305],{"class":264}," {",[255,307,308],{"class":264}," major",[255,310,311],{"class":264}," =",[255,313,314],{"class":264}," minor",[255,316,311],{"class":264},[255,318,319],{"class":264}," patch",[255,321,311],{"class":264},[255,323,324],{"class":264}," 0",[255,326,327],{"class":264}," }\n",[255,329,331],{"class":257,"line":330},3,[255,332,333],{"class":274},"{\n",[255,335,337,341,344,348,351,354],{"class":257,"line":336},4,[255,338,340],{"class":339},"sqF6k","  if",[255,342,343],{"class":274}," (",[255,345,347],{"class":346},"smONe","$0",[255,349,350],{"class":274}," ~ \u002FBREAKING-CHANGE:|",[255,352,353],{"class":261},"^[^\\s:]+!:\u002F",[255,355,356],{"class":274},") {\n",[255,358,360,363,366,369,371,373,375],{"class":257,"line":359},5,[255,361,362],{"class":261},"    major++",[255,364,365],{"class":274},"; ",[255,367,368],{"class":261},"minor",[255,370,311],{"class":264},[255,372,319],{"class":264},[255,374,311],{"class":264},[255,376,377],{"class":264}," 0\n",[255,379,381,384,387,390,392,395,398,401,404,407,410,413,416,418,421,423,426,429,432,435,438,442,445],{"class":257,"line":380},6,[255,382,383],{"class":274},"  } ",[255,385,386],{"class":339},"else",[255,388,389],{"class":339}," if",[255,391,343],{"class":274},[255,393,394],{"class":261},"tolower($0",[255,396,397],{"class":274},") ",[255,399,400],{"class":261},"~",[255,402,403],{"class":264}," \u002F^",[255,405,406],{"class":274},"(",[255,408,409],{"class":261},"feat",[255,411,412],{"class":274},"|",[255,414,415],{"class":261},"build",[255,417,412],{"class":274},[255,419,420],{"class":261},"ci",[255,422,412],{"class":274},[255,424,425],{"class":261},"chore",[255,427,428],{"class":274},")",[255,430,431],{"class":264},"[^",[255,433,434],{"class":274},"\\s",[255,436,437],{"class":264},":]",[255,439,441],{"class":440},"s8HWQ","*",[255,443,444],{"class":264},":\u002F",[255,446,356],{"class":274},[255,448,450],{"class":257,"line":449},7,[255,451,452],{"class":261},"    minor++\n",[255,454,456,458,460,462,464,466,468,470,473,475,477,479,481],{"class":257,"line":455},8,[255,457,383],{"class":274},[255,459,386],{"class":339},[255,461,389],{"class":339},[255,463,343],{"class":274},[255,465,394],{"class":261},[255,467,397],{"class":274},[255,469,400],{"class":261},[255,471,472],{"class":264}," \u002F^fix[^",[255,474,434],{"class":274},[255,476,437],{"class":264},[255,478,441],{"class":440},[255,480,444],{"class":264},[255,482,356],{"class":274},[255,484,486],{"class":257,"line":485},9,[255,487,488],{"class":261},"    patch++\n",[255,490,492,494,496,498,500,502,505,507,509,511,514,516,519,521,524,527,529,531,533,535,537,539,542],{"class":257,"line":491},10,[255,493,383],{"class":274},[255,495,386],{"class":339},[255,497,389],{"class":339},[255,499,343],{"class":274},[255,501,394],{"class":261},[255,503,504],{"class":274},") !",[255,506,400],{"class":261},[255,508,403],{"class":264},[255,510,406],{"class":274},[255,512,513],{"class":261},"docs",[255,515,412],{"class":274},[255,517,518],{"class":261},"style",[255,520,412],{"class":274},[255,522,523],{"class":261},"refactor",[255,525,526],{"class":274},"|test)",[255,528,431],{"class":264},[255,530,434],{"class":274},[255,532,437],{"class":264},[255,534,441],{"class":440},[255,536,197],{"class":264},[255,538,412],{"class":274},[255,540,541],{"class":261},"fixup!\u002F",[255,543,356],{"class":274},[255,545,547,550,553,556,559],{"class":257,"line":546},11,[255,548,549],{"class":274},"    printf ",[255,551,552],{"class":264},"\"Invalid type: %s\\n\",",[255,554,555],{"class":346}," $0",[255,557,558],{"class":274}," > ",[255,560,561],{"class":264},"\"\u002Fdev\u002Fstderr\"\n",[255,563,565],{"class":257,"line":564},12,[255,566,567],{"class":274},"  }\n",[255,569,571],{"class":257,"line":570},13,[255,572,573],{"class":274},"}\n",[255,575,577,580,582,585,588,591,594,596],{"class":257,"line":576},14,[255,578,579],{"class":261},"END",[255,581,305],{"class":264},[255,583,584],{"class":264}," printf",[255,586,587],{"class":264}," \"v%d.%d.%d\\n\",",[255,589,590],{"class":264}," major,",[255,592,593],{"class":264}," minor,",[255,595,319],{"class":264},[255,597,327],{"class":264},[137,599,600,601,604],{},"Don’t be tempted to adjust the awk script to support “BREAKING CHANGE” because\ngit will never print it using the ",[220,602,603],{},"%(trailers)"," placeholder since whitespace\nis not a valid character for git trailer keys.",[159,606,607],{"id":62},"Go",[137,609,610],{},"How do we integrate this into a our Go project?\nDuring the build process, we can set the value of an uninitialized variable:",[247,612,614],{"className":249,"code":613,"language":251,"meta":147,"style":147},"go build -ldflags=\"-X 'importpath.name=value'\"\n",[220,615,616],{"__ignoreMap":147},[255,617,618,620,623],{"class":257,"line":258},[255,619,62],{"class":261},[255,621,622],{"class":264}," build",[255,624,625],{"class":264}," -ldflags=\"-X 'importpath.name=value'\"\n",[159,627,628],{"id":628},"make",[137,630,631],{},"Finally, I like to use a Makefile with a “build” and “version” target:",[247,633,635],{"className":249,"code":634,"language":251,"meta":147,"style":147},"build: clean ## Build binary\nifeq ($(shell git rev-parse --is-inside-work-tree 2>\u002Fdev\u002Fnull),true)\n  @$(eval VERSION := $(shell $(MAKE) version --no-print-directory))\n  go build --ldflags '-X app.version.Version='$(VERSION)\nelse\n  $(error Not in a git repository)\nendif\n\nversion: ## Make version\nifeq ($(shell git rev-parse --is-inside-work-tree 2>\u002Fdev\u002Fnull),true)\n  @git log --reverse --pretty='format:%s %(trailers:key=BREAKING-CHANGE,separator=%x2C)' | \\\n    awk 'BEGIN { major = minor = patch = 0 } { \\\n      if ($$0 ~ \u002FBREAKING-CHANGE:|^[^\\s:]+!:\u002F) { \\\n        major++; minor = patch = 0 \\\n      } else if (tolower($$0) ~ \u002F^(feat|build|ci|chore)[^\\s:]*:\u002F) { \\\n        minor++ \\\n      } else if (tolower($$0) ~ \u002F^fix[^\\s:]*:\u002F) { \\\n        patch++ \\\n      } else if (tolower($$0) !~ \u002F^(docs|style|refactor|test)[^\\s:]*:|fixup!\u002F) { \\\n        printf \"Invalid type: %s\\n\", $$0 > \"\u002Fdev\u002Fstderr\" \\\n      } \\\n    } END { printf \"v%d.%d.%d\\n\", major, minor, patch }'\nelse\n  $(error Not in a git repository)\nendif\n",[220,636,637,648,673,706,728,733,755,760,766,774,792,807,815,820,825,831,837,843,849,855,861,867,873,878,895],{"__ignoreMap":147},[255,638,639,642,645],{"class":257,"line":258},[255,640,641],{"class":261},"build:",[255,643,644],{"class":264}," clean",[255,646,647],{"class":296}," ## Build binary\n",[255,649,650,653,656,658,661,664,667,670],{"class":257,"line":278},[255,651,652],{"class":261},"ifeq",[255,654,655],{"class":274}," ($(shell ",[255,657,93],{"class":264},[255,659,660],{"class":264}," rev-parse",[255,662,663],{"class":264}," --is-inside-work-tree",[255,665,666],{"class":274}," 2>",[255,668,669],{"class":264},"\u002Fdev\u002Fnull",[255,671,672],{"class":274},"),true)\n",[255,674,675,678,681,684,687,690,692,695,697,700,703],{"class":257,"line":330},[255,676,677],{"class":261},"  @$(eval",[255,679,680],{"class":264}," VERSION",[255,682,683],{"class":264}," :=",[255,685,686],{"class":274}," $(",[255,688,689],{"class":261},"shell",[255,691,686],{"class":274},[255,693,694],{"class":261},"MAKE",[255,696,397],{"class":274},[255,698,699],{"class":264},"version",[255,701,702],{"class":264}," --no-print-directory",[255,704,705],{"class":274},"))\n",[255,707,708,711,713,716,719,722,725],{"class":257,"line":336},[255,709,710],{"class":261},"  go",[255,712,622],{"class":264},[255,714,715],{"class":264}," --ldflags",[255,717,718],{"class":264}," '-X app.version.Version='",[255,720,721],{"class":274},"$(",[255,723,724],{"class":261},"VERSION",[255,726,727],{"class":274},")\n",[255,729,730],{"class":257,"line":359},[255,731,732],{"class":339},"else\n",[255,734,735,738,741,744,747,750,753],{"class":257,"line":380},[255,736,737],{"class":261},"  $(error",[255,739,740],{"class":264}," Not",[255,742,743],{"class":264}," in",[255,745,746],{"class":264}," a",[255,748,749],{"class":264}," git",[255,751,752],{"class":264}," repository",[255,754,727],{"class":274},[255,756,757],{"class":257,"line":449},[255,758,759],{"class":261},"endif\n",[255,761,762],{"class":257,"line":455},[255,763,765],{"emptyLinePlaceholder":764},true,"\n",[255,767,768,771],{"class":257,"line":485},[255,769,770],{"class":261},"version:",[255,772,773],{"class":296}," ## Make version\n",[255,775,776,778,780,782,784,786,788,790],{"class":257,"line":491},[255,777,652],{"class":261},[255,779,655],{"class":274},[255,781,93],{"class":264},[255,783,660],{"class":264},[255,785,663],{"class":264},[255,787,666],{"class":274},[255,789,669],{"class":264},[255,791,672],{"class":274},[255,793,794,797,799,801,804],{"class":257,"line":546},[255,795,796],{"class":261},"  @git",[255,798,265],{"class":264},[255,800,268],{"class":264},[255,802,803],{"class":264}," --pretty='format:%s %(trailers:key=BREAKING-CHANGE,separator=%x2C)'",[255,805,806],{"class":274}," | \\\n",[255,808,809,812],{"class":257,"line":564},[255,810,811],{"class":261},"    awk",[255,813,814],{"class":264}," 'BEGIN { major = minor = patch = 0 } { \\\n",[255,816,817],{"class":257,"line":570},[255,818,819],{"class":264},"      if ($$0 ~ \u002FBREAKING-CHANGE:|^[^\\s:]+!:\u002F) { \\\n",[255,821,822],{"class":257,"line":576},[255,823,824],{"class":264},"        major++; minor = patch = 0 \\\n",[255,826,828],{"class":257,"line":827},15,[255,829,830],{"class":264},"      } else if (tolower($$0) ~ \u002F^(feat|build|ci|chore)[^\\s:]*:\u002F) { \\\n",[255,832,834],{"class":257,"line":833},16,[255,835,836],{"class":264},"        minor++ \\\n",[255,838,840],{"class":257,"line":839},17,[255,841,842],{"class":264},"      } else if (tolower($$0) ~ \u002F^fix[^\\s:]*:\u002F) { \\\n",[255,844,846],{"class":257,"line":845},18,[255,847,848],{"class":264},"        patch++ \\\n",[255,850,852],{"class":257,"line":851},19,[255,853,854],{"class":264},"      } else if (tolower($$0) !~ \u002F^(docs|style|refactor|test)[^\\s:]*:|fixup!\u002F) { \\\n",[255,856,858],{"class":257,"line":857},20,[255,859,860],{"class":264},"        printf \"Invalid type: %s\\n\", $$0 > \"\u002Fdev\u002Fstderr\" \\\n",[255,862,864],{"class":257,"line":863},21,[255,865,866],{"class":264},"      } \\\n",[255,868,870],{"class":257,"line":869},22,[255,871,872],{"class":264},"    } END { printf \"v%d.%d.%d\\n\", major, minor, patch }'\n",[255,874,876],{"class":257,"line":875},23,[255,877,732],{"class":339},[255,879,881,883,885,887,889,891,893],{"class":257,"line":880},24,[255,882,737],{"class":261},[255,884,740],{"class":264},[255,886,743],{"class":264},[255,888,746],{"class":264},[255,890,749],{"class":264},[255,892,752],{"class":264},[255,894,727],{"class":274},[255,896,898],{"class":257,"line":897},25,[255,899,759],{"class":261},[159,901,903],{"id":902},"conclusion","Conclusion",[137,905,906],{},"With just about ten lines of awk, we have a fairly robust implementation of an\nautomated version management system using Conventional Commits and Semantic\nVersioning.",[518,908,909],{},"html pre.shiki code .stHQG, html code.shiki .stHQG{--shiki-default:#00DAEF}html pre.shiki code .se2J0, html code.shiki .se2J0{--shiki-default:#FFD493}html pre.shiki code .sLo_3, html code.shiki .sLo_3{--shiki-default:#EEF0F9}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sy89t, html code.shiki .sy89t{--shiki-default:#EEF0F98F;--shiki-default-font-style:italic}html pre.shiki code .sqF6k, html code.shiki .sqF6k{--shiki-default:#54B9FF}html pre.shiki code .smONe, html code.shiki .smONe{--shiki-default:#4BF3C8;--shiki-default-font-style:italic}html pre.shiki code .s8HWQ, html code.shiki .s8HWQ{--shiki-default:#ACAFFF}",{"title":147,"searchDepth":278,"depth":278,"links":911},[912,913,914,915,916,917],{"id":161,"depth":278,"text":162},{"id":214,"depth":278,"text":215},{"id":72,"depth":278,"text":72},{"id":62,"depth":278,"text":607},{"id":628,"depth":278,"text":628},{"id":902,"depth":278,"text":903},{},{"title":44,"description":91},"blog\u002Fmake-version",[72,93,62,94],{"sm":96,"md":97,"lg":98},"G6jVPogS_dBX3li4vHYdoGA6CQHo5UtBktc5_UTWwrs",[],{"id":4,"title":5,"author":926,"description":14,"extension":15,"meta":927,"repository":928,"stem":21,"__hash__":22},{"name":7,"github":8,"gitlab":9,"email":10,"linkedin":11,"mastodon":12,"bio":13},{},{"url":18,"git":19,"branch":20},1793313045135]