2020-03-22-org-mode-website.html (31532B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <!-- Sep 03, 2024 --> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1" /> 7 <title>Migrating to an org-mode website</title> 8 <meta name="author" content="Vincent Demeester" /> 9 <meta name="generator" content="Org Mode" /> 10 <link rel='icon' type='image/x-icon' href='/images/favicon.ico'/> 11 <meta name='viewport' content='width=device-width, initial-scale=1'> 12 <link rel='stylesheet' href='/css/new.css' type='text/css'/> 13 <link rel='stylesheet' href='/css/syntax.css' type='text/css'/> 14 <link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' /> 15 </head> 16 <body> 17 <main id="content" class="content"> 18 <header> 19 <h1 class="title">Migrating to an org-mode website</h1> 20 </header><section id="outline-container-Introduction" class="outline-2"> 21 <h2 id="Introduction">Introduction</h2> 22 <div class="outline-text-2" id="text-Introduction"> 23 <p> 24 This is a story… a story of me changing the way I code and publish my website. In the 25 past, I’ve switch from <a href="https://vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll/">Jekyll</a> to <a href="https://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/">“<code>orgmode</code> and Jekyll”</a> to <a href="https://vincent.demeester.fr/posts/2015-05-09-migration-to-hugo/">Hugo</a> (sorry those are written 26 in french). The past year, I’ve written and documented myself a little bit about 27 <a href="https://www.theminimalists.com/minimalism/">minimalism</a> and <a href="https://www.goodreads.com/book/show/40672036-digital-minimalism">digital minimalism</a>. Although I don’t see myself as a minimalist, it helped 28 me realize some issues I had. 29 </p> 30 31 <p> 32 I also realized if I want to write more, I need to lower the barrier between writing and 33 publishing my content ; <i>if I want it to be published, of course</i>. This <i>post</i> is about 34 what I’m putting in place for this, with a premise : I spend my life in <a href="https://www.gnu.org/software/emacs/">Emacs</a> and thus in 35 <a href="https://orgmode.org/"><code>orgmode</code></a>. And <a href="https://orgmode.org/"><code>orgmode</code></a> is feature-full and has this badass feature : <code>org-publish</code>. 36 </p> 37 38 <p> 39 To build and publish this website, we will <i>try</i> to rely on a reproducible setup, meaning 40 <a href="https://www.gnu.org/software/emacs/">Emacs</a> and <a href="https://orgmode.org/"><code>orgmode</code></a> of course, <a href="https://www.gnu.org/software/make/">GNU Make</a> of course <b>but</b> most importantly, <a href="https://nixos.org/nix/">Nix</a> (in the near 41 future 👼). 42 </p> 43 44 <div class='drawer update'> 45 <h6>Update</h6> 46 <p> 47 There is now an article about it, that uses literate programming: <a href="../articles/meta_publishing_this_website.html">publishing this 48 website</a>. The content of the post might no be up-to-date at some point. 49 </p> 50 </div> 51 </div> 52 </section> 53 <section id="outline-container-Requirements" class="outline-2"> 54 <h2 id="Requirements">Requirements</h2> 55 <div class="outline-text-2" id="text-Requirements"> 56 <p> 57 Let’s list the requirements I feel I have for my website: 58 </p> 59 60 <dl class="org-dl"> 61 <dt>Full control over the URL of the published posts.</dt><dd>This is a golden rule of the web: should I change the publishing system, I want to be 62 able to stick to the same URLs or else all external references would be broken. This is 63 a big no-no and in my opinion it makes most blogging systems unacceptable.</dd> 64 <dt>Top-notch Org support.</dt><dd>I believe generators like Jekyll and Hugo only have partial Org support. You end up 65 requiring some conversion tooling to get the job done.</dd> 66 <dt>Simple publishing pipeline.</dt><dd>I want the generation process to be as simple as possible. This is important for 67 maintenance. Should I someday switch host, I want to be sure that I can set up the same 68 pipeline.</dd> 69 <dt>Full control over the publishing system.</dt><dd>I want maximum control over the generation process. I don’t want to be restricted by a 70 non-Turing-complete configuration file or a dumb programming language.</dd> 71 <dt>Ease of use.</dt><dd>The process as a whole must be as immediate and friction-less as possible, or else I 72 take the risk of feeling too lazy to publish new posts and update the content.</dd> 73 <dt>Hackability.</dt><dd>Last but not least, and this probably supersedes all other requirements: The system must 74 be hackable. Lisp-based systems are prime contenders in that area.</dd> 75 </dl> 76 </div> 77 </section> 78 <section id="outline-container-Organizing" class="outline-2"> 79 <h2 id="Organizing"><span class="done DONE">DONE</span> Organizing</h2> 80 <div class="outline-text-2" id="text-Organizing"> 81 <div class='drawer logbook'> 82 <h6>Logbook</h6> 83 <ul class="org-ul"> 84 <li>State “DONE” from “TODO” <span class="timestamp-wrapper"><span class="timestamp">[2020-03-21 Sat 17:57]</span></span></li> 85 </ul> 86 </div> 87 88 <p> 89 Let’s describe what I do want to publish here: 90 </p> 91 92 <dl class="org-dl"> 93 <dt>Posts</dt><dd>this is what we call <i>blog</i> these days : short to medium article that are valid 94 at a point of time, as may contain <i>deprecated</i> content, or content that do not reflect 95 my views at a later point in time.</dd> 96 <dt>Articles</dt><dd>medium to long article about a topic. Those should be up-to-date or 97 explicitly mark as deprecated or invalid. <i>In a ideal world this is my <b>ready for the 98 public</b> knowledge database, a bit like <a href="https://braindump.jethro.dev/">Jethro’s Braindump</a></i>.</dd> 99 <dt>Configurations</dt><dd>medium to long article about my configurations. Those are base on my 100 <code>home</code> <i>configuration</i> mono-repository, and usually follow literate programming 101 principles.</dd> 102 <dt>About</dt><dd>an about page about the author of the website (aka <a href="https://vincent.demeester.fr">me</a>), linking external 103 contributions (GitHub/Gitlab/… profiles, Talks, …).</dd> 104 </dl> 105 </div> 106 </section> 107 <section id="outline-container-Publishing" class="outline-2"> 108 <h2 id="Publishing"><span class="done DONE">DONE</span> Publishing</h2> 109 <div class="outline-text-2" id="text-Publishing"> 110 <div class='drawer logbook'> 111 <h6>Logbook</h6> 112 <ul class="org-ul"> 113 <li>State “DONE” from “TODO” <span class="timestamp-wrapper"><span class="timestamp">[2020-03-25 Wed 15:54]</span></span></li> 114 </ul> 115 </div> 116 117 <p> 118 As said above, the goal is to publish everything using only <a href="https://www.gnu.org/software/emacs/">Emacs</a> and <a href="https://orgmode.org/"><code>orgmode</code></a> (with the 119 help of some standard GNU tools). 120 </p> 121 122 <p> 123 The <a href="file:///home/vincent/src/sbr/publish.el"><code>publish.el</code></a> file is where all the magic happens: 124 </p> 125 126 <ul class="org-ul"> 127 <li><p> 128 I want to generate something that is <code>html5</code> (almost?). The <i>preamble</i>, <i>content</i> and 129 <i>postamble</i> <code>div</code> can be customized using <code>org-html-div</code>. Same goes for the <i>container</i> 130 element that is used for “wrapping top level sections”, it is customized using 131 <code>org-html-container-helement</code> (we want <code><section></code>). There is a few additional variable 132 that I might document one day 😛. 133 </p> 134 135 <div class="org-src-container"> 136 <pre class="src src-emacs-lisp">(setq org-export-use-babel nil) 137 (setq org-link-abbrev-alist '(("att" . org-attach-expand-link))) 138 139 ;; setting to nil, avoids "Author: x" at the bottom 140 (setq org-export-with-section-numbers nil 141 org-export-with-smart-quotes t 142 org-export-with-toc nil) 143 144 (defvar sbr-date-format "%b %d, %Y") 145 146 (setq org-html-divs '((preamble "header" "top") 147 (content "main" "content") 148 (postamble "footer" "postamble")) 149 org-html-container-element "section" 150 org-html-metadata-timestamp-format sbr-date-format 151 org-html-checkbox-type 'unicode 152 org-html-html5-fancy t 153 org-html-doctype "html5" 154 org-html-htmlize-output-type 'css 155 org-html-htmlize-font-prefix "org-" 156 org-src-fontify-natively t 157 org-html-coding-system 'utf-8-unix) 158 </pre> 159 </div></li> 160 161 <li>Part of the <code><head></code>, preamble and postamble are customized for the website. 162 <dl class="org-dl"> 163 <dt><code>head</code></dt><dd><div class="org-src-container"> 164 <pre class="src src-emacs-lisp">(defvar sbr-website-html-head 165 "<link rel='icon' type='image/x-icon' href='/images/favicon.ico'/> 166 <meta name='viewport' content='width=device-width, initial-scale=1'> 167 <link rel='stylesheet' href='/css/new.css' type='text/css'/> 168 <link rel='stylesheet' href='/css/syntax.css' type='text/css'/> 169 <link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />") 170 </pre> 171 </div></dd> 172 <dt>premable</dt><dd><div class="org-src-container"> 173 <pre class="src src-emacs-lisp">(defun sbr-website-html-preamble (plist) 174 "PLIST: An entry." 175 ;; Skip adding subtitle to the post if :KEYWORDS don't have 'post' has a 176 ;; keyword 177 (when (string-match-p "post" (format "%s" (plist-get plist :keywords))) 178 (plist-put plist 179 :subtitle (format "Published on %s by %s." 180 (org-export-get-date plist sbr-date-format) 181 (car (plist-get plist :author))))) 182 183 ;; Below content will be added anyways 184 "<nav> 185 <img src=\"/images/favicon.ico\" id=\"sitelogo\"/> <a href='/'>home</a> / 186 <a href='/posts/'>posts</a> (<a href='/index.xml'>rss</a>) / 187 <a href='/articles/'>articles</a> / 188 <a href='/configurations/'>configurations</a> / 189 <a href='https://dl.sbr.pm/'>files</a> / 190 <a href='/about/'>about</a></li> 191 </nav>") 192 </pre> 193 </div></dd> 194 <dt>postamble</dt><dd><div class="org-src-container"> 195 <pre class="src src-emacs-lisp">(defvar sbr-website-html-postamble 196 "<footer> 197 <span class='questions'>Questions, comments ? Please use my <a href=\"https://lists.sr.ht/~vdemeester/public-inbox\">public inbox</a> by sending a plain-text email to <a href=\"mailto:~vdemeester/public-inbox@lists.sr.ht\">~vdemeester/public-inbox@lists.sr.ht</a>.</span> 198 <span class='opinions'>Opinions stated here are my own and do not express the views of my employer, spouse, children, pets, neighbors, secret crushes, favorite authors, or anyone else who is not me. And maybe not even me, depending on how old this is.</span> 199 <span class='copyright'> 200 Content and design by Vincent Demeester 201 (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>) 202 </span><br /> 203 <span class='engine'> 204 Powered by <a href='https://www.gnu.org/software/emacs/'>Gnu Emacs</a> and <a href='https://orgmode.org'>orgmode</a> 205 </span> 206 </footer>") 207 </pre> 208 </div></dd> 209 </dl></li> 210 <li><p> 211 <code>orgmode</code> is able to generate a site-map. This is what we are going to use to generate 212 the index files for <code>posts/</code> and <code>articles</code> mainly. 213 </p> 214 <div class="org-src-container"> 215 <pre class="src src-emacs-lisp">(defun sbr/org-sitemap-format-entry (entry style project) 216 "Format posts with author and published data in the index page. 217 218 ENTRY: file-name 219 STYLE: 220 PROJECT: `posts in this case." 221 (cond ((not (directory-name-p entry)) 222 (format "%s — [[file:%s][%s]] 223 :PROPERTIES: 224 :PUBDATE: [%s] 225 :END:" 226 (format-time-string "%Y-%m-%d" 227 (org-publish-find-date entry project)) 228 entry 229 (org-publish-find-title entry project) 230 (format-time-string "%Y-%m-%d" 231 (org-publish-find-date entry project)))) 232 ((eq style 'tree) (file-name-nondirectory (directory-file-name entry))) 233 (t entry))) 234 235 (defun sbr/org-publish-sitemap (title list) 236 "" 237 (concat "#+TITLE: " title "\n\n" 238 (org-list-to-subtree list))) 239 </pre> 240 </div></li> 241 <li><p> 242 <code>orgmode</code> is able to generate a rss, with <code>ox-rss</code>. This is what we are going to use to 243 generate the rss files for <code>posts</code> and <code>articles</code>. This is <span class="underline">heavily</span> customized. 244 </p> 245 <div class="org-src-container"> 246 <pre class="src src-emacs-lisp">(defun sbr/org-get-first-paragraph (file) 247 "Get string content of first paragraph of file." 248 (ignore-errors 249 (with-temp-buffer 250 (insert-file-contents file) 251 (goto-char (point-min)) 252 (show-all) 253 (let ((first-begin (progn 254 (org-forward-heading-same-level 1) 255 (next-line) 256 (point))) 257 (first-end (progn 258 (org-next-visible-heading 1) 259 (point)))) 260 (buffer-substring first-begin first-end))))) 261 262 (defun sbr/org-rss-publish-to-rss (plist filename pub-dir) 263 "Prepare rss.org file before exporting." 264 (let* ((postsdir (plist-get plist :base-directory))) 265 (with-current-buffer (find-file filename) 266 (erase-buffer) 267 (insert "#+TITLE: Posts\n") 268 (insert "#+AUTHOR: Vincent Demeester\n") 269 (insert "#+OPTIONS: toc:nil\n") 270 (let* ((files-all 271 (reverse (directory-files "." nil 272 "[0-9-]+.*\\.org$"))) 273 (files (subseq files-all 0 (min (length files-all) 30)))) 274 (message (format "foo: %s" filename)) 275 (dolist (post files) 276 (let* ((post-file post) 277 (post-title (org-publish-find-title post-file plist)) 278 (preview-str (sbr/org-get-first-paragraph post-file)) 279 (date (replace-regexp-in-string 280 "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*" 281 "\\1" post))) 282 (insert (concat "* [[file:" postsdir "/" post "][" post-title "]]\n\n")) 283 (org-set-property "ID" post) 284 (org-set-property "RSS_TITLE" post-title) 285 ;; ox-rss prepends html-link-home to permalink 286 (org-set-property "RSS_PERMALINK" 287 (concat postsdir "/" 288 (file-name-sans-extension post) 289 ".html")) 290 (org-set-property 291 "PUBDATE" 292 (format-time-string 293 "<%Y-%m-%d %a %H:%M>" 294 (org-time-string-to-time 295 (replace-regexp-in-string 296 "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*" 297 "\\1" post)))) 298 (insert preview-str) 299 (newline 1) 300 (insert (concat "[[file:" postsdir "/" post "][(Read more)]]\n\n")))) 301 (save-buffer)))) 302 (let ((user-mail-address "t") 303 (org-export-with-broken-links t) 304 (org-rss-use-entry-url-as-guid nil)) 305 (org-rss-publish-to-rss plist filename pub-dir))) 306 </pre> 307 </div></li> 308 <li><p> 309 Finally let’s set the <code>org-publish-project-alist</code> to publish our projects 310 </p> 311 <div class="org-src-container"> 312 <pre class="src src-emacs-lisp">(setq org-publish-project-alist 313 `(("posts" 314 :base-directory "posts" 315 :base-extension "org" 316 :recursive t 317 :publishing-function org-html-publish-to-html 318 :publishing-directory "./public/posts" 319 :exclude ,(regexp-opt '("README.org" "draft")) 320 :auto-sitemap t 321 :with-footnotes t 322 :with-toc nil 323 :with-drawers t 324 :sitemap-filename "index.org" 325 :sitemap-title "Posts" 326 :sitemap-format-entry sbr/org-sitemap-format-entry 327 :sitemap-style list 328 :sitemap-sort-files anti-chronologically 329 :sitemap-function sbr/org-publish-sitemap 330 :html-head-include-scripts nil 331 :html-head-include-default-style nil 332 :html-head ,sbr-website-html-head 333 :html-preamble sbr-website-html-preamble 334 :html-postamble ,sbr-website-html-postamble) 335 ("posts-rss" 336 :base-directory "posts" 337 :base-extension "org" 338 :recursive t 339 :html-link-home "https://vincent.demeester.fr/" 340 :rss-link-home "https://vincent.demeester.fr/posts/" 341 :html-link-use-abs-url t 342 :rss-extension "xml" 343 :publishing-directory "./public" 344 :publishing-function (sbr/org-rss-publish-to-rss) 345 :section-number nil 346 :exclude ".*" 347 :include ("index.org")) 348 ("articles" 349 :base-directory "articles" 350 :base-extension "org" 351 :recursive t 352 :publishing-function org-html-publish-to-html 353 :publishing-directory "./public/articles" 354 :exclude ,(regexp-opt '("README.org" "draft")) 355 :auto-sitemap t 356 :with-footnotes t 357 :with-toc nil 358 :with-drawers t 359 :sitemap-filename "sitemap.org" 360 :sitemap-title "Articles" 361 :sitemap-style tree 362 :sitemap-sort-files anti-chronologically 363 ;;:sitemap-format-entry sbr/org-sitemap-format-entry 364 ;;:sitemap-function sbr/org-publish-sitemap 365 :html-head-include-scripts nil 366 :html-head-include-default-style nil 367 :html-head ,sbr-website-html-head 368 :html-preamble sbr-website-html-preamble 369 :html-postamble ,sbr-website-html-postamble) 370 ("articles-assets" 371 :exclude ,(regexp-opt '("*.org")) 372 :base-directory "articles" 373 :base-extension ,site-attachments 374 :publishing-directory "./public/articles" 375 :publishing-function org-publish-attachment 376 :recursive t) 377 ("about" 378 :base-directory "about" 379 :base-extension "org" 380 :exclude ,(regexp-opt '("README.org" "draft")) 381 :index-filename "index.org" 382 :recursive nil 383 :with-footnotes t 384 :with-toc nil 385 :with-drawers t 386 :publishing-function org-html-publish-to-html 387 :publishing-directory "./public/about" 388 :html-head-include-scripts nil 389 :html-head-include-default-style nil 390 :html-head ,sbr-website-html-head 391 :html-preamble sbr-website-html-preamble 392 :html-postamble ,sbr-website-html-postamble) 393 ("index" 394 :base-directory "" 395 :base-extension "org" 396 :exclude ,(regexp-opt '("README.org" "draft")) 397 :index-filename "index.org" 398 :recursive nil 399 :with-footnotes t 400 :with-toc nil 401 :with-drawers t 402 :with-title nil 403 :publishing-function org-html-publish-to-html 404 :publishing-directory "./public" 405 :html-head-include-scripts nil 406 :html-head-include-default-style nil 407 :html-head ,sbr-website-html-head 408 :html-preamble sbr-website-html-preamble 409 :html-postamble ,sbr-website-html-postamble) 410 ("css" 411 :base-directory "./css" 412 :base-extension ,site-attachments 413 :recursive t 414 :publishing-directory "./public/css" 415 :publishing-function org-publish-attachment 416 :recursive t) 417 ("images" 418 :base-directory "./images" 419 :base-extension ,site-attachments 420 :publishing-directory "./public/images" 421 :publishing-function org-publish-attachment 422 :recursive t) 423 ("assets" 424 :base-directory "./assets" 425 :base-extension ,site-attachments 426 :publishing-directory "./public/assets" 427 :publishing-function org-publish-attachment 428 :recursive t) 429 ("legacy" 430 :base-directory "./legacy" 431 :base-extension ,site-attachments 432 :publishing-directory "./public/" 433 :publishing-function org-publish-attachment 434 :recursive t) 435 ("all" :components ("posts" "about" "index" "articles" "articles-assets" "css" "images" "assets" "legacy" "posts-rss")))) 436 </pre> 437 </div></li> 438 </ul> 439 440 <p> 441 Here are some <i>inspiration</i> I took for this publishing code: 442 </p> 443 444 <ul class="org-ul"> 445 <li><a href="https://thibaultmarin.github.io/blog/posts/2016-11-13-Personal_website_in_org.html">Personal website in org</a></li> 446 <li><a href="https://vicarie.in/posts/blogging-with-org.html">Blogging with Org publishing</a></li> 447 <li><a href="https://ambrevar.xyz/blog-architecture/">A blog in pure Org/Lisp</a></li> 448 <li><a href="https://zngguvnf.org/2017-07-13--blogging-with-org-static-blog.html">Blogging with org-static-blog</a></li> 449 <li><a href="https://bastibe.de/2013-11-13-blogging-with-emacs.html">Blogging with Emacs</a></li> 450 <li><a href="https://gjhenrique.com/meta.html">Blogging with org-mode and Gitlab Pages</a></li> 451 </ul> 452 </div> 453 </section> 454 <section id="outline-container-Styling" class="outline-2"> 455 <h2 id="Styling"><span class="done DONE">DONE</span> Styling</h2> 456 <div class="outline-text-2" id="text-Styling"> 457 <div class='drawer logbook'> 458 <h6>Logbook</h6> 459 <ul class="org-ul"> 460 <li>State “DONE” from “STARTED” <span class="timestamp-wrapper"><span class="timestamp">[2020-03-23 Mon 19:02]</span></span></li> 461 </ul> 462 </div> 463 464 <p> 465 The style of the website has be as simple as possible, and also really light. This means: 466 </p> 467 <ul class="org-ul"> 468 <li>use default system font as much as possible</li> 469 <li>have a small stylesheet, rely on the default as much as we can</li> 470 </ul> 471 472 <p> 473 In addition, I want support for: 474 </p> 475 <ul class="org-ul"> 476 <li>side notes</li> 477 <li>code syntax highlight</li> 478 <li>table of content</li> 479 </ul> 480 481 <p> 482 The inspiration for this website, in term of style are the following: 483 </p> 484 <ul class="org-ul"> 485 <li><a href="https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/">Vincent Demeester</a></li> 486 <li><a href="https://braindump.jethro.dev/zettels/zettelkasten/">Jethro’s Braindump</a></li> 487 <li><a href="https://hamberg.no/gtd/">GTD in 15 minutes – A Pragmatic Guide to Getting Things Done</a></li> 488 <li><a href="https://www.inkandswitch.com/local-first.html">Local-first software: You own your data, in spite of the cloud</a></li> 489 <li><a href="https://archive.casouri.cat/note/2018/blog-in-org-mode-revisited/index.html">Blog in Org Mode, Revisited</a></li> 490 <li><a href="https://kind.sigs.k8s.io/">kind</a></li> 491 <li><a href="http://willcrichton.net/notes/idioms-of-dynamic-languages/">Idioms of Dynamic Languages | Will Crichton</a></li> 492 <li><a href="https://peter.bourgon.org/blog/2019/09/11/programming-with-errors.html">Peter Bourgon · Programming with errors</a></li> 493 <li><a href="https://johv.dk/blog/bare-metal-assembly-tutorial.html">Getting started with bare-metal assembly — Jonas Hvid</a></li> 494 </ul> 495 496 <p> 497 To be able to define the style a bit, let’s try some things below. From this point on, 498 this is random content just to try my style out. 👼 499 </p> 500 501 <p> 502 There is more in <a href="../articles/sandbox.html">the sandbox</a>. 503 </p> 504 505 <hr> 506 507 <div class="abstract" id="org026d63b"> 508 <p> 509 Let’s dig into how I setup my development environment when working on <code>tektoncd/pipeline</code> 510 </p> 511 512 </div> 513 514 <nav id="table-of-contents" role="doc-toc"> 515 <h2>Table of Contents</h2> 516 <div id="text-table-of-contents" role="doc-toc"> 517 <ul> 518 <li><a href="#Introduction">Introduction</a></li> 519 <li><a href="#Requirements">Requirements</a></li> 520 <li><a href="#Organizing"><span class="done DONE">DONE</span> Organizing</a></li> 521 <li><a href="#Publishing"><span class="done DONE">DONE</span> Publishing</a></li> 522 <li><a href="#Styling"><span class="done DONE">DONE</span> Styling</a> 523 <ul> 524 <li><a href="#sub-heading%201">sub-heading 1</a></li> 525 <li><a href="#sub-heading%202">sub-heading 2</a></li> 526 </ul> 527 </li> 528 <li><a href="#What%27s%20next%20%3F">What’s next ?</a></li> 529 </ul> 530 </div> 531 </nav> 532 </div> 533 <div id="outline-container-sub-heading%201" class="outline-3"> 534 <h3 id="sub-heading%201">sub-heading 1</h3> 535 <div class="outline-text-3" id="text-sub-heading%201"> 536 <p> 537 Checking for errors is <b>very common</b> in Go, having <code>Comparison</code> function for it was a requirement. 538 </p> 539 540 <aside id="org13d2778"> 541 <p> 542 This is a side note. If collection is a string, item must also be a string, and is 543 compared using <code>strings.Contains()</code>. If collection is a Map, contains will succeed if item 544 is a key in the map. 545 </p> 546 </aside> 547 548 <ul class="org-ul"> 549 <li><code>Error</code> fails if the error is <code>nil</code> <b>or</b> the error message is not the expected one.</li> 550 <li><code>ErrorContains</code> fails if the error is <code>nil</code> <b>or</b> the error message does not contain the expected substring.</li> 551 <li><code>ErrorType</code> fails if the error is <code>nil</code> <b>or</b> the error type is not the expected type.</li> 552 </ul> 553 554 <p> 555 Let’s first look at the most used : <code>Error</code> and <code>ErrorContains</code>. 556 When you’re working on <code>pipeline</code>, usually you want : 557 </p> 558 559 <ol class="org-ol"> 560 <li>make sure it compiles : <code>go build -v ./..</code></li> 561 <li>Running unit tests : <code>go test ./...</code> (bonus use <a href="https://github.com/vdemeester/ram"><code>ram</code></a> for continuous testing)</li> 562 <li><p> 563 End-to-end tests : <code>go test -tags e2e ./...</code> (or simply using `./test/` package) 564 </p> 565 566 <p> 567 <b>Make sure you re-deploy before running the e2e tests</b> using <code>ko apply -f ./config</code>, 568 otherwise you’re testing the wrong code. 569 </p></li> 570 </ol> 571 572 <div class="org-src-container"> 573 <pre class="src src-go">var err error 574 // will fail with : expected an error, got nil 575 assert.Check(t, cmp.Error(err, "message in a bottle")) 576 err = errors.Wrap(errors.New("other"), "wrapped") 577 // will fail with : expected error "other", got "wrapped: other" 578 assert.Check(t, cmp.Error(err, "other")) 579 // will succeed 580 assert.Check(t, cmp.ErrorContains(err, "other")) 581 </pre> 582 </div> 583 584 585 <figure id="org202916a"> 586 <img src="../images/emacs/2020-02-29-13-46-08.png" alt="2020-02-29-13-46-08.png" width="100%"> 587 588 <figcaption><span class="figure-number">Figure 1: </span>This is the caption for the next figure link (or table)</figcaption> 589 </figure> 590 591 <p> 592 If this is the case, then what makes dynamic languages feel easy? Can we take what we learn in answering this question and improve the ergonomics of our static languages? For example, in 2018, I don’t think there’s as strong an argument for “you don’t have to write out the types,” since modern type inference eliminates most of the keystrokes required (even though many major languages still lack such facilities). Plus, saving a few keystrokes does not seem like a critical bottleneck in the programming process. 593 </p> 594 595 596 <figure id="org079eac9"> 597 <img src="../images/emacs/2020-02-29-14-41-59.png" alt="2020-02-29-14-41-59.png"> 598 599 </figure> 600 </div> 601 </div> 602 <div id="outline-container-sub-heading%202" class="outline-3"> 603 <h3 id="sub-heading%202">sub-heading 2</h3> 604 <div class="outline-text-3" id="text-sub-heading%202"> 605 <p> 606 Some content from my other org-mode files. 607 </p> 608 609 <div class="description" id="orga53ead1"> 610 <p> 611 I already wrote 2 previous posts about golang and testing. It’s something I care deeply about and I wanted to continue 612 writing about it. It took me a bit more time than I thought, but getting back to it. Since the <a href="http://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/">last post</a>, Daniel 613 Nephin 614 and I worked (but mainly Daniel 🤗) on bootstrapping a testing helper library. 615 </p> 616 617 </div> 618 619 <blockquote> 620 <p> 621 Package assert provides assertions for comparing expected values to actual values. When 622 assertion fails a helpful error message is printed. 623 </p> 624 </blockquote> 625 626 <p> 627 There is already some good <code>testing</code> helpers in the Go ecosystem : <a href="https://github.com/stretchr/testify"><code>testify</code></a>, <a href="http://labix.org/gocheck"><code>gocheck</code></a>, 628 <a href="https://github.com/onsi/ginkgo"><code>ginkgo</code></a> and a lot more — so why create a new one ? There is multiple reason for it, most 629 of them can be seen in the following <a href="https://github.com/gotestyourself/gotest.tools/issues/49#issuecomment-362436026">GitHub issue</a>. 630 </p> 631 632 <p> 633 <a href="https://github.com/dnephin/">Daniel</a> also wrote a very useful <sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>converter if your code base is currently using <code>testify</code> : 634 <code>gty-migrate-from-testify</code>. 635 </p> 636 637 <div class="org-src-container"> 638 <pre class="src src-sh">$ go get -u gotest.tools/assert/cmd/gty-migrate-from-testify 639 # […] 640 $ go list \ 641 -f '{{.ImportPath}} {{if .XTestGoFiles}}{{"\n"}}{{.ImportPath}}_test{{end}}' \ 642 ./... | xargs gty-migrate-from-testify 643 </pre> 644 </div> 645 646 <p> 647 We’ll Use <code>Assert</code> for the rest of the section but any example here would work with 648 <code>Check</code> too. When we said <code>Comparison</code> above, it’s mainly the <a href="https://godoc.org/gotest.tools/assert#BoolOrComparison">BoolOrComparison</a> interface — 649 it can either be a boolean expression, or a <a href="https://godoc.org/gotest.tools/assert/cmp#Comparison">cmp.Comparison</a> type. <code>Assert</code> and <code>Check</code> code 650 will be <i>smart</i> enough to detect which one it is. 651 </p> 652 653 <div class="org-src-container"> 654 <pre class="src src-go">assert.Assert(t, ok) 655 assert.Assert(t, err != nil) 656 assert.Assert(t, foo.IsBar()) 657 </pre> 658 </div> 659 </div> 660 </div> 661 </section> 662 <section id="outline-container-What%27s%20next%20%3F" class="outline-2"> 663 <h2 id="What%27s%20next%20%3F">What’s next ?</h2> 664 <div class="outline-text-2" id="text-What%27s%20next%20%3F"> 665 <p> 666 One thing is to import old blog posts from <a href="https://vincent.demeester.fr">vincent.demeester.fr</a>. This is easily done with 667 <a href="https://pandoc.org/">Pandoc</a> and a small bash loop — and some manual adjusting later on 😛. 668 </p> 669 670 <div class="org-src-container"> 671 <pre class="src src-bash">for post in ~/src/github.com/vdemeester/blog/content/posts/*.md; do 672 pandoc -f markdown -t org -o posts/$(basename -s .md ${post}).org ${post} 673 done 674 </pre> 675 </div> 676 677 678 <p> 679 What is still <i>to do</i> after this initial take. 680 </p> 681 682 <ul class="org-ul"> 683 <li class="off">☐ List <code>FILETAGS</code> for taximony</li> 684 <li class="off">☐ Maybe use <a href="https://css-tricks.com/snippets/css/complete-guide-grid/">css grid</a> for the UI</li> 685 </ul> 686 </div> 687 </section> 688 <div id="footnotes"> 689 <h2 class="footnotes">Footnotes: </h2> 690 <div id="text-footnotes"> 691 692 <div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara"> 693 foo is bar, bar is baz 694 </p></div></div> 695 696 697 </div> 698 </div></main> 699 <footer id="postamble" class="status"> 700 <footer> 701 <small><a href="/" rel="history">Index</a> • <a href="/sitemap.html">Sitemap</a> • <a href="https://dl.sbr.pm/">Files</a></small><br/> 702 <small class='questions'>Questions, comments ? Please use my <a href="https://lists.sr.ht/~vdemeester/public-inbox">public inbox</a> by sending a plain-text email to <a href="mailto:~vdemeester/public-inbox@lists.sr.ht">~vdemeester/public-inbox@lists.sr.ht</a>.</small><br/> 703 <small class='copyright'> 704 Content and design by Vincent Demeester 705 (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>) 706 </small><br /> 707 </footer> 708 </footer> 709 </body> 710 </html>