<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Thibaut Rousseau&#x27;s Blog</title>
    <link rel="self" type="application/atom+xml" href="https://blog.thibaut-rousseau.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-01-05T00:00:00+00:00</updated>
    <id>https://blog.thibaut-rousseau.com/atom.xml</id>
    <entry xml:lang="en">
        <title>The most popular Go dependency is…</title>
        <published>2026-01-05T00:00:00+00:00</published>
        <updated>2026-01-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/the-most-popular-go-dependency-is/"/>
        <id>https://blog.thibaut-rousseau.com/blog/the-most-popular-go-dependency-is/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/the-most-popular-go-dependency-is/">&lt;p&gt;…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;stretchr&#x2F;testify&quot;&gt;testify&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;As you know, destination is not as important as the journey, so now that we got this out of the way, bear with me for the rest of this article, and I’ll give you the top 10, and many more stats 😊 You might even learn a few things along the way!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Without usage statistics, finding useful and reliable dependencies can be a bit of a challenge. In the Go community, we basically have to rely either:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;on &quot;brand&quot; name reputation: there are some very well known packages (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;gin&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;spf13&#x2F;cobra&quot;&gt;cobra&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;stretchr&#x2F;testify&quot;&gt;testify&lt;&#x2F;a&gt;…) and organizations (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google?q=&amp;amp;type=all&amp;amp;language=go&amp;amp;sort=stargazers&quot;&gt;Google&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gorilla&quot;&gt;gorilla&lt;&#x2F;a&gt;…) that we can trust,&lt;&#x2F;li&gt;
&lt;li&gt;or on side metrics such as number of GitHub stars, number of open issues, last activity, and more.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All of this can sometimes help get a feeling of how widely used and trusted a Go module is, but we could get more. What I personally want is knowing how many times a module is actually required as a project dependency to get a feeling of how &quot;battle-tested&quot; a library is. But to do this, I would need to build a graph of the whole (open source) ecosystem, which would be insane… You can see where this is going 😉&lt;&#x2F;p&gt;
&lt;aside class=&quot;my-5 p-5 bg-white shadow-sm rounded-md&quot;&gt;
  The source code for this project is available on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&quot;&gt;github.com&#x2F;Thiht&#x2F;go-stats&lt;&#x2F;a&gt;.
It uses Go as a primary language (obviously!), and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&quot;&gt;Neo4j&lt;&#x2F;a&gt; as a database.
&lt;&#x2F;aside&gt;
&lt;h2 id=&quot;mapping-the-go-ecosystem&quot;&gt;Mapping the Go ecosystem&lt;&#x2F;h2&gt;
&lt;p&gt;My &lt;strong&gt;first idea&lt;&#x2F;strong&gt; was to build a list of repositories (a seed) to use as a starting point. The goal was to read the dependencies of these modules from their &lt;code&gt;go.mod&lt;&#x2F;code&gt;, download each of them, &lt;span class=&quot;text-sm&quot;&gt;read the dependencies of these modules from their &lt;code&gt;go.mod&lt;&#x2F;code&gt;, download each of them, &lt;&#x2F;span&gt;&lt;span class=&quot;text-2xs&quot;&gt;read the dependencies of these modules from their &lt;code&gt;go.mod&lt;&#x2F;code&gt;, download each of…&lt;&#x2F;span&gt; well, you know the deal.&lt;&#x2F;p&gt;
&lt;p&gt;I implemented this idea on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;tree&#x2F;v1&quot;&gt;&lt;code&gt;v1&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; branch of my repository using mainly &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;evanli.github.io&#x2F;Github-Ranking&#x2F;&quot;&gt;Github-Ranking&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;awesome-go.com&quot;&gt;awesome-go&lt;&#x2F;a&gt; as sources for building the seed. I ultimately abandoned the idea because of a few shortcomings:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the sample is largely incomplete,&lt;&#x2F;li&gt;
&lt;li&gt;cloning so many Git repositories to find their &lt;code&gt;go.mod&lt;&#x2F;code&gt; is reaaally painful and slow,&lt;&#x2F;li&gt;
&lt;li&gt;and it’s particularly biased towards repositories hosted on GitHub.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Luckily for me, I came up with a &lt;strong&gt;second idea&lt;&#x2F;strong&gt;: the Go modules ecosystem relies on a centralized public proxy, so surely they expose some information on these modules. And they in fact do so! The proxy APIs are documented on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;proxy.golang.org&#x2F;&quot;&gt;proxy.golang.org&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;ref&#x2F;mod#goproxy-protocol&quot;&gt;proxy.golang.org&lt;&#x2F;a&gt; exposes metadata on each module (versions, latest, mod file…),&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;index.golang.org&quot;&gt;index.golang.org&lt;&#x2F;a&gt; exposes a feed of all the published module versions since the introduction of the Go proxy (&lt;code&gt;2019-04-10T19:08:52.997264Z&lt;&#x2F;code&gt;, if you want to make sure not to forget its birthday).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I used this information to locally download the whole index (module names and versions) since 2019. The downloaded data is available in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;tree&#x2F;main&#x2F;data&#x2F;goproxy-modules&quot;&gt;goproxy-modules&lt;&#x2F;a&gt;. This can be used as a local immutable cache.&lt;&#x2F;p&gt;
&lt;aside class=&quot;my-5 p-5 bg-white shadow-sm rounded-md&quot;&gt;
  For the full implementation details, see:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;blob&#x2F;main&#x2F;cmd&#x2F;list-goproxy-modules.go&quot;&gt;&lt;code&gt;list-goproxy-modules.go&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;blob&#x2F;main&#x2F;goproxy&#x2F;goproxy.go&quot;&gt;&lt;code&gt;goproxy.go&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;aside&gt;
&lt;p&gt;With all this data available locally, the seed is now pretty much exhaustive, and more suitable for data analysis. The processing now simply consists of iterating over every single module, downloading their &lt;code&gt;go.mod&lt;&#x2F;code&gt; file and listing their dependencies. The resulting graph can then trivially be inserted in a specialized graph database like Neo4j.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deep-diving&quot;&gt;Deep diving&lt;&#x2F;h2&gt;
&lt;img class=&quot;float-right w-30&quot; src=&quot;.&#x2F;neo4j.png&quot; alt=&quot;Neo4j logo&quot; &#x2F;&gt;
&lt;p&gt;Neo4j is a graph oriented database. It means that unlike relational databases, it works on... graphs. The primary way to store data in Neo4j is using nodes and relationships. This specialized data structure makes it extremely simple to model, and more importantly query huge graphs.&lt;&#x2F;p&gt;
&lt;aside class=&quot;my-5 p-5 bg-white shadow-sm rounded-md&quot;&gt;
  If you want to experiment with Neo4j, I would recommend using the go-stats &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;blob&#x2F;main&#x2F;docker-compose.yml&quot;&gt;&lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; file. You can then open &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;localhost:7474&#x2F;browser&#x2F;&quot;&gt;localhost:7474&lt;&#x2F;a&gt; (no credentials needed) to use the Neo4j browser.
&lt;&#x2F;aside&gt;
&lt;p&gt;Neo4j, like many NoSQL databases, is schemaless, meaning you don&#x27;t need to define a schema before creating data. That doesn&#x27;t mean we don&#x27;t need a schema, so let&#x27;s see what we need!&lt;&#x2F;p&gt;
&lt;pre class=&quot;mermaid bg-transparent mx-auto w-50&quot;&gt;
erDiagram
    Module {
        string name
        string version
    }

    Module ||--o{ Module : DEPENDS_ON
&lt;&#x2F;pre&gt;
&lt;p&gt;A Go module is basically identified by its name (eg. &lt;code&gt;github.com&#x2F;stretchr&#x2F;testify&lt;&#x2F;code&gt; or &lt;code&gt;go.yaml.in&#x2F;yaml&#x2F;v4&lt;&#x2F;code&gt;) and its version. Each module can depend on other modules. We can add more properties to our nodes later on as needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;creating-nodes&quot;&gt;Creating nodes&lt;&#x2F;h3&gt;
&lt;p&gt;Neo4j uses &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&#x2F;docs&#x2F;cypher-manual&#x2F;current&#x2F;introduction&#x2F;&quot;&gt;Cypher&lt;&#x2F;a&gt; as a query language. Inserting data with Cypher can be done with the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&#x2F;docs&#x2F;cypher-manual&#x2F;current&#x2F;clauses&#x2F;create&#x2F;&quot;&gt;&lt;code&gt;CREATE&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; clause, but in go-stats I&#x27;ve decided to use the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&#x2F;docs&#x2F;cypher-manual&#x2F;current&#x2F;clauses&#x2F;merge&#x2F;&quot;&gt;&lt;code&gt;MERGE&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; clause instead because it behaves as an upsert, letting you update or do nothing in case a node already exists.&lt;&#x2F;p&gt;
&lt;p&gt;The basic Cypher query to upsert a module node is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MERGE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;:Module&lt;&#x2F;code&gt; is a label attached to the node. You can think of it as the type of the node. &lt;code&gt;name&lt;&#x2F;code&gt; and &lt;code&gt;version&lt;&#x2F;code&gt; are properties of the node, they&#x27;re the data belonging to each specific node.&lt;&#x2F;p&gt;
&lt;p&gt;To make sure we can&#x27;t create multiple nodes with the same name-version pair, a unicity constraint is needed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;CREATE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; CONSTRAINT module_identity IF NOT EXISTS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FOR&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;REQUIRE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;IS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; UNIQUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Thanks to this constraint, if &lt;code&gt;MERGE&lt;&#x2F;code&gt; is called a second time with the same &lt;code&gt;name&lt;&#x2F;code&gt; and &lt;code&gt;version&lt;&#x2F;code&gt; properties, it won&#x27;t do anything.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;creating-relationships&quot;&gt;Creating relationships&lt;&#x2F;h3&gt;
&lt;p&gt;We can then create the dependency relationships between our module nodes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependencyName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependencyVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependentName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependentVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MERGE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DEPENDS_ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This query will:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;find modules that were created earlier using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&#x2F;docs&#x2F;cypher-manual&#x2F;current&#x2F;clauses&#x2F;match&#x2F;&quot;&gt;&lt;code&gt;MATCH&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; clause and assign them to &lt;code&gt;dependency&lt;&#x2F;code&gt; and &lt;code&gt;dependent&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;create the directed relationship between them using the &lt;code&gt;-[:DEPENDS_ON]-&amp;gt;&lt;&#x2F;code&gt; syntax.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The Go index is naturally sorted chronologically.
So as long as we iterate over it sequentially, it means that if a module (&lt;em&gt;dependent&lt;&#x2F;em&gt;) depends on another module (&lt;em&gt;dependency&lt;&#x2F;em&gt;), then &lt;em&gt;dependency&lt;&#x2F;em&gt; was necessarily added to the graph before &lt;em&gt;dependent&lt;&#x2F;em&gt;.
If this condition doesn&#x27;t hold for some reason (if we were to decide to parallelize the insertions for example), we could simply rewrite the query as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MERGE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependencyName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependencyVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MERGE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependentName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependentVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MERGE&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DEPENDS_ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using &lt;code&gt;MERGE&lt;&#x2F;code&gt; instead of &lt;code&gt;MATCH&lt;&#x2F;code&gt; would ensure the node gets created if it doesn&#x27;t exist already.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;These queries are simplified (but close!) variants of what I actually did in go-stats. The main difference is that I enriched the nodes with some additional properties:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;version timestamp,&lt;&#x2F;li&gt;
&lt;li&gt;latest version,&lt;&#x2F;li&gt;
&lt;li&gt;semantic version splitting (major, minor, patch, label),&lt;&#x2F;li&gt;
&lt;li&gt;host, organisation, and more.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;aside class=&quot;my-5 p-5 bg-white shadow-sm rounded-md&quot;&gt;
  For the full implementation details, see: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&#x2F;blob&#x2F;main&#x2F;cmd&#x2F;process-modules.go&quot;&gt;&lt;code&gt;process-modules.go&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;aside&gt;
&lt;h2 id=&quot;digging-into-the-graph&quot;&gt;Digging into the graph&lt;&#x2F;h2&gt;
&lt;p&gt;After running go-stats for a few days, I ended up with a graph of roughly &lt;strong&gt;40 million nodes&lt;&#x2F;strong&gt;, and &lt;strong&gt;400 million relationships&lt;&#x2F;strong&gt;… that&#x27;s quite a lot!
The first thing these numbers tell us is that Go modules have &lt;strong&gt;10 direct dependencies on average&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;img class=&quot;mx-auto w-100 shadow-md rounded-md&quot; src=&quot;.&#x2F;data-analyst.jpg&quot; alt=&quot;Meme showing a dog in a scientist outfit saying: I&#x27;m a data analyst now&quot;&gt;
&lt;p&gt;For more interesting stats, let&#x27;s write some Cypher, shall we?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;indexing&quot;&gt;Indexing&lt;&#x2F;h3&gt;
&lt;p&gt;With this volume of data, the absolute first thing to do (that I clearly didn&#x27;t do at first) is to create relevant indexes. I was initially under the impression that the &lt;code&gt;module_identity&lt;&#x2F;code&gt; constraint previously created would also act as an index for &lt;code&gt;:Module.name&lt;&#x2F;code&gt; since it&#x27;s a composite unique index. I was wrong, and creating a specific index was necessary:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;CREATE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; INDEX module_name_idx IF NOT EXISTS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FOR&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ON&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I created other indexes as needed, and to do so the Cypher &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neo4j.com&#x2F;docs&#x2F;cypher-manual&#x2F;current&#x2F;planning-and-tuning&#x2F;&quot;&gt;&lt;code&gt;PROFILE&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; was a tremendous help.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;find-the-direct-dependents-of-a-module&quot;&gt;Find the direct dependents of a module&lt;&#x2F;h3&gt;
&lt;p&gt;As a warm-up, and to learn a bit more about Cypher, let&#x27;s list the dependents of a specific module:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;github.com&#x2F;pkg&#x2F;errors&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;v0.9.1&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DEPENDS_ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependent&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;isLatest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependent&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;versionTime&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;year&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; year&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;COUNT&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; nbDependents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I chose &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pkg&#x2F;errors&#x2F;tree&#x2F;v0.9.1&quot;&gt;&lt;code&gt;github.com&#x2F;pkg&#x2F;errors@v0.9.1&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; because it&#x27;s a module that was deprecated long ago, I find it interesting to know how much it&#x27;s still used in the wild. Let&#x27;s break the query down line by line:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;MATCH (dependency:Module { name: &#x27;xxx&#x27;, version: &#x27;xxx&#x27; })&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;finds the module node (we know it&#x27;s unique because of the constraint we declared earlier) with the given &lt;code&gt;name&lt;&#x2F;code&gt; and &lt;code&gt;version&lt;&#x2F;code&gt;. This is equivalent to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;xxx&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;AND&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;xxx&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;MATCH (dependency)&amp;lt;-[:DEPENDS_ON]-(dependent:Module)&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;finds the module nodes with a direct &lt;code&gt;DEPENDS_ON&lt;&#x2F;code&gt; relationship towards &lt;code&gt;dependency&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;WHERE dependent.isLatest&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;keeps &lt;code&gt;dependents&lt;&#x2F;code&gt; modules that are in their latest version. This is useful because for any module &lt;code&gt;x&lt;&#x2F;code&gt; depends on &lt;code&gt;github.com&#x2F;pkg&#x2F;errors@v0.9.1&lt;&#x2F;code&gt;, we don&#x27;t want to count all the versions of &lt;code&gt;x&lt;&#x2F;code&gt; that depend on it. The latest is more relevant to us.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RETURN dependent.versionTime.year AS year, COUNT(dependent) AS nbDependents&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;simply counts the total dependents of &lt;code&gt;github.com&#x2F;pkg&#x2F;errors@v0.9.1&lt;&#x2F;code&gt; and group by release year of the dependent. If we wanted to list them, we could write:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependent&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependentName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;ORDER BY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependentName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;year&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;nbDependents&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2019&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2020&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;6,774&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2021&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;10,680&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2022&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;11,747&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2023&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;8,992&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2024&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;12,220&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2025&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;16,001&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;That&#x27;s a lot of dependents for a dead library!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;find-the-transitive-dependents-of-a-module&quot;&gt;Find the transitive dependents of a module&lt;&#x2F;h3&gt;
&lt;p&gt;Neo4j really shines at graph traversal. Navigating relationships transitively requires virtually no changes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;github.com&#x2F;pkg&#x2F;errors&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &amp;#39;v0.9.1&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DEPENDS_ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;*1&lt;&#x2F;span&gt;&lt;span&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependent&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;isLatest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; COUNT&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; nbDependents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The only difference with the previous query is &lt;code&gt;*1..&lt;&#x2F;code&gt;, asking Neo4j to follow the &lt;code&gt;DEPENDS_ON&lt;&#x2F;code&gt; relationship transitively. We could also limit it to 2 levels with &lt;code&gt;*1..2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I find this interesting, because in the case of the query for direct dependencies, if we used a relational database, the SQL query would be pretty simple:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;SELECT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; COUNT&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span&gt; nb_dependents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; dependencies d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;JOIN&lt;&#x2F;span&gt;&lt;span&gt; modules m &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; d&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;dependent_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;JOIN&lt;&#x2F;span&gt;&lt;span&gt; modules dependency &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; d&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;dependency_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;github.com&#x2F;pkg&#x2F;errors&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  AND&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;v0.9.1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  AND&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;is_latest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;but what&#x27;s as simple as &lt;code&gt;*1..&lt;&#x2F;code&gt; in Cypher would make a dramatically more complex SQL query:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;-- Example using a recursive CTE, I&amp;#39;m not sure every SGBDR implements it in the same way&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;WITH RECURSIVE&lt;&#x2F;span&gt;&lt;span&gt; dependents_cte &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  SELECT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; AS&lt;&#x2F;span&gt;&lt;span&gt; dependency_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  FROM&lt;&#x2F;span&gt;&lt;span&gt; modules m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;github.com&#x2F;pkg&#x2F;errors&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    AND&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;v0.9.1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  UNION ALL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  SELECT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; d&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;dependent_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  FROM&lt;&#x2F;span&gt;&lt;span&gt; dependencies d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  JOIN&lt;&#x2F;span&gt;&lt;span&gt; dependents_cte cte &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; d&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;dependency_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; cte&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;dependency_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;SELECT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; COUNT&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;DISTINCT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span&gt; nb_dependents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; modules m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; IN&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;SELECT&lt;&#x2F;span&gt;&lt;span&gt; dependency_id &lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FROM&lt;&#x2F;span&gt;&lt;span&gt; dependents_cte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  AND&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; m&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;is_latest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;top-10-most-used-dependencies&quot;&gt;Top 10 most used dependencies&lt;&#x2F;h3&gt;
&lt;p&gt;Using the constructs from above, the query is once again pretty similar.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;cypher&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;MATCH&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DEPENDS_ON&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependency&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Module&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependent&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;isLatest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;RETURN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependency&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dependencyName&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;COUNT&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;dependent&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;AS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; nbDependents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;ORDER BY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; nbDependents&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; DESC&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;LIMIT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;dependencyName&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;nbDependents&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;stretchr&#x2F;testify&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;259,237&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;google&#x2F;uuid&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;104,877&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;golang.org&#x2F;x&#x2F;crypto&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;100,633&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;google.golang.org&#x2F;grpc&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;97,228&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;spf13&#x2F;cobra&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;93,062&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;pkg&#x2F;errors&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;92,491&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;golang.org&#x2F;x&#x2F;net&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;76,722&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;google.golang.org&#x2F;protobuf&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;74,971&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;sirupsen&#x2F;logrus&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;71,730&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;github.com&#x2F;spf13&#x2F;viper&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;64,174&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;github.com&#x2F;stretchr&#x2F;testify&lt;&#x2F;code&gt; is comfortably ahead of other dependencies as the most used in the open source Go ecosystem.
Unsurprisingly, &lt;code&gt;github.com&#x2F;google&#x2F;uuid&lt;&#x2F;code&gt; is also a staple library used pretty much everywhere.
The &lt;code&gt;golang.org&#x2F;x&#x2F;&lt;&#x2F;code&gt; dependencies also hold a strong place as the extended stdlib, as well as the infamous &lt;code&gt;github.com&#x2F;pkg&#x2F;errors&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To get more insights, you can download the &lt;a href=&quot;https:&#x2F;&#x2F;blog.thibaut-rousseau.com&#x2F;blog&#x2F;the-most-popular-go-dependency-is&#x2F;.&#x2F;top100.csv&quot;&gt;top 100 as a CSV file&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;If you want to run your own queries, feel free to download my Neo4j dump via BitTorrent:&lt;&#x2F;p&gt;
&lt;div class=&quot;flex items-center bg-white shadow-sm rounded-md py-3&quot;&gt;
  &lt;div class=&quot;flex-shrink-0 text-xl px-5&quot;&gt;
    &lt;img src=&quot;&#x2F;icons&#x2F;bittorrent-color.svg&quot; class=&quot;w-4 !m-0&quot; &#x2F;&gt;
  &lt;&#x2F;div&gt;

  &lt;div class=&quot;flex flex-col justify-start&quot;&gt;
    &lt;a href=&quot;.&amp;#x2F;go-stats-neo4j-dump-20260105.torrent&quot;&gt;go-stats-neo4j-dump-20260105.tar&lt;&#x2F;a&gt;
    &lt;span class=&quot;text-sm&quot;&gt;(11.21 GiB)&lt;&#x2F;span&gt;
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;To load it in a Neo4j instance, please follow these instructions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;clone &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&quot;&gt;&lt;code&gt;go-stats&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;copy the dump file to &lt;code&gt;neo4j&#x2F;backups&#x2F;neo4j.dump&lt;&#x2F;code&gt; (the filename is important),&lt;&#x2F;li&gt;
&lt;li&gt;execute &lt;code&gt;task neo4j:backup:load&lt;&#x2F;code&gt;, this will write the data to &lt;code&gt;neo4j&#x2F;data&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;run &lt;code&gt;task neo4j:start&lt;&#x2F;code&gt; to start Neo4j.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can then open &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;localhost:7474&#x2F;browser&#x2F;&quot;&gt;localhost:7474&lt;&#x2F;a&gt; (no credentials needed) to use the Neo4j browser.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;blog.thibaut-rousseau.com&#x2F;blog&#x2F;the-most-popular-go-dependency-is&#x2F;.&#x2F;neo4j-browser.png&quot; alt=&quot;Neo4j browser&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;that-s-all-folks&quot;&gt;That&#x27;s all Folks!&lt;&#x2F;h2&gt;
&lt;p&gt;I hope you had a good time reading this post, and that you learned a thing or two!&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ll probably continue playing around with this side-project as I have more ideas to explore. Specifically, I&#x27;d like to enrich the graph with more metadata, such as GitHub stars and tags. So stay tuned to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;go-stats&quot;&gt;GitHub project&lt;&#x2F;a&gt; if you want to follow the upcoming developments.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>SQL Transactions in Go: The Good Way</title>
        <published>2025-01-21T00:00:00+00:00</published>
        <updated>2025-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/sql-transactions-in-go-the-good-way/"/>
        <id>https://blog.thibaut-rousseau.com/blog/sql-transactions-in-go-the-good-way/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/sql-transactions-in-go-the-good-way/">&lt;p&gt;In my last work experience, I designed what I consider a pretty cool and efficient way to manage database transactions across a Go codebase. In a nutshell, I wanted to use database transactions in my business logic without exposing database internals.&lt;&#x2F;p&gt;
&lt;p&gt;After dogfooding a solution for a while, I extracted it, improved it, and enriched it, to finally release it as the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;transactor&quot;&gt;transactor&lt;&#x2F;a&gt; library. This library is now tested across the most common relational databases (PostgreSQL, MySQL, SQLite, MSSQL and Oracle), and is compatible with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;database&#x2F;sql&quot;&gt;&lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;jmoiron&#x2F;sqlx&quot;&gt;jmoiron&#x2F;sqlx&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;jackc&#x2F;pgx&#x2F;v5&quot;&gt;jackc&#x2F;pgx&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In my current job, transactors are now our main (soon to be unique!) way to manage database transactions, which is why I feel comfortable talking about this method more widely.&lt;&#x2F;p&gt;
&lt;p&gt;In this article, I’ll walk you through the design and implementation so you can either use the lib, or adapt it and extend it depending on your needs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-exactly-do-we-need-a-library&quot;&gt;Why exactly do we need a library?&lt;&#x2F;h2&gt;
&lt;p&gt;In web services &#x2F; APIs, it’s customary to use some kind of layered architecture, like Clean Architecture, Hexagonal Architecture, or anything that boils down to a three-tier architecture. In Go, it’s something like:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;u&gt;Handlers&lt;&#x2F;u&gt; (a.k.a. controllers): the entrypoints of the API, usually the only layer allowed to be aware of the router and current HTTP request&#x2F;response handlers,&lt;&#x2F;li&gt;
&lt;li&gt;&lt;u&gt;Services&lt;&#x2F;u&gt; (a.k.a. usecases): the business layer, where the domain logic lives,&lt;&#x2F;li&gt;
&lt;li&gt;&lt;u&gt;Stores&lt;&#x2F;u&gt; (a.k.a. repositories, data access, storage, persistence…): the layer communicating with databases, caches, filesystems, and so on. It’s usually the only layer allowed to be aware of the concrete storage systems. In practice, it means it’s the only place where &lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt;, your DB driver, or your ORM should be imported.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Whether transactions should be allowed in the services layer is sometimes up for debate, as they’re somewhat tied to the DB implementation. In Go, a transaction is represented by &lt;code&gt;*sql.Tx&lt;&#x2F;code&gt;, but according to the definitions above, using it directly in the services layer would require importing &lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt;. This is why it’s sometimes accepted that transactions should live in the storage layer only.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I disagree with this.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I strongly believe transactions can be used both in the storage layer and in the services layer, for different reasons. Specifically, transactions can be a part of the business logic, and are a part of an interface contract. But I also believe neither &lt;code&gt;*sql.DB&lt;&#x2F;code&gt;, &lt;code&gt;*sql.Tx&lt;&#x2F;code&gt; or &lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt; should be imported by the services. This is the reason why I needed to create an object that could be injected to the services, allowing them to make transactions safely across many stores, without exposing any implementation details. The solution to this problem is the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;transactor&quot;&gt;transactor&lt;&#x2F;a&gt; library.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-transactor-interface&quot;&gt;The Transactor interface&lt;&#x2F;h2&gt;
&lt;p&gt;A transactor lets you create a transactional context, represented by a closure. It’s defined as a simple interface:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; Transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A transactor implements this interface. We can then inject it in a service, and use it to make some transactional calls completely transparently, without knowing anything about the database. Let&#x27;s look at some sample code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-code-without-a-transaction&quot;&gt;Example code without a transaction&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stores&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Balance&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; IncreaseBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;GetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;SetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way to manage a financial balance is not great for several reasons, but let’s focus on it as a case study. Without going into too much details (“what transactions are used for” is not the topic here).&lt;&#x2F;p&gt;
&lt;p&gt;This first version, doesn’t use a transaction. It makes it possible to get an inconsistent resulting balance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-code-using-a-transactor&quot;&gt;Example code using a transactor&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stores&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Balance&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; Transactor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; IncreaseBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;GetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;SetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This second version wraps &lt;code&gt;GetBalance&lt;&#x2F;code&gt; and &lt;code&gt;SetBalance&lt;&#x2F;code&gt; in a transaction, essentially making the operation atomic.&lt;&#x2F;p&gt;
&lt;p&gt;The changes made when using the Transactor are minimal, as they just impact 2-3 lines in this case, but here’s what happens in details:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;WithinTransaction&lt;&#x2F;code&gt; accepts a context and a callback:
&lt;ol&gt;
&lt;li&gt;The context will be enriched with the transaction ; more on that later,&lt;&#x2F;li&gt;
&lt;li&gt;The enriched context is passed to the callback, which I call a &lt;em&gt;transactional context,&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;To keep the changes minimal, the parent context is shadowed in the callback by naming it &lt;code&gt;ctx&lt;&#x2F;code&gt; ; this has no unintended effects, and makes it impossible to misuse the transactor (eg. by using the wrong context in one of the calls),&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;WithinTransaction&lt;&#x2F;code&gt; does essentially three things to manage the transaction workflow:
&lt;ol&gt;
&lt;li&gt;Begin the transaction,&lt;&#x2F;li&gt;
&lt;li&gt;Execute the callback,&lt;&#x2F;li&gt;
&lt;li&gt;Commit, or Rollback the transaction.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This workflow is detailed in the flowchart below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;mermaid bg-transparent&quot;&gt;
flowchart TD
  Start((Start)) --&gt; Begin[&quot;Begin transaction&quot;]
  Begin --&gt; ErrBegin{Error?}
  ErrBegin -- no --&gt; Callback[&quot;Execute callback&quot;]
  ErrBegin -- yes --&gt; RetErrBegin([Return error])
  Callback --&gt; ErrCallback{Error?}
  ErrCallback -- no --&gt; Commit
  ErrCallback -- yes --&gt; RollbackCallback[&quot;Rollback&quot;]
  RollbackCallback --&gt; RetErrCallback([Return error])
  Commit --&gt; ErrCommit{Error?}
  ErrCommit -- no --&gt; Success([Success])
  ErrCommit -- yes --&gt; RetErrCommit([Return error])

  classDef failure stroke:#eb2f06,fill:#e55039
  classDef success stroke:#079992,fill:#38ada9
  class RetErrBegin,RollbackCallback,RetErrCallback,RetErrCommit failure
  class Success success
&lt;&#x2F;pre&gt;
&lt;p&gt;And voilà! The transactor makes &lt;strong&gt;using transactions fool proof, and extremely easy&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;And the best thing is, there’s more.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nesting-transactions&quot;&gt;Nesting transactions&lt;&#x2F;h2&gt;
&lt;p&gt;Transactors, when properly implemented, make it possible to deal with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Nested_transaction&quot;&gt;&lt;strong&gt;nested transactions&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;. The implementation for nested transactions varies depending on the database, but the transactor library provides an implementation for all the major systems.&lt;&#x2F;p&gt;
&lt;p&gt;You can use a transactor anywhere, and you don’t have to worry if the methods you call use a transactor themselves. As an example, the following code making use of our previously defined &lt;code&gt;IncreaseBalance&lt;&#x2F;code&gt; is completely valid and working as you would expect:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; TransferBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  fromAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; toAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;DecreaseBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; fromAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IncreaseBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; toAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or, more generally:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; Do some stuff before the nested transaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; Do some stuff inside the nested transaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; Handle rollback of the nested transaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; Do some stuff after the nested transaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; Handle rollback of the main transaction&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just like that, we made &lt;strong&gt;transactional methods composable inside a larger transaction&lt;&#x2F;strong&gt;. Compared to other ways of dealing with transactions, such as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unit_of_work&quot;&gt;Unit of Work&lt;&#x2F;a&gt;, transactors make it really straightforward to compose anything inside a transaction: store methods, methods across different stores (working on the same storage system), or business services.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementing-a-database-sql-transactor&quot;&gt;Implementing a &lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt; Transactor&lt;&#x2F;h2&gt;
&lt;p&gt;To illustrate the above, let’s dive into the implementation of a transactor for &lt;code&gt;database&#x2F;sql&lt;&#x2F;code&gt; from the Go standard library.&lt;&#x2F;p&gt;
&lt;p&gt;The full reference implementation can be found in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;transactor&#x2F;blob&#x2F;main&#x2F;stdlib&#x2F;transactor.go&quot;&gt;transactor&#x2F;stdlib&#x2F;transactor.go&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The very basic structure we’ll need will evolve a bit as we go, but let’s get started:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;package&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; transactor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;database&#x2F;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; Transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _ Transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; NewTransactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; txFunc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this first step, we create a private &lt;code&gt;transactor&lt;&#x2F;code&gt; implementing the &lt;code&gt;Transactor&lt;&#x2F;code&gt; interface.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;*sql.DB&lt;&#x2F;code&gt; is a database handler representing an active connection to the database. It’s the result of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;database&#x2F;sql#Open&quot;&gt;&lt;code&gt;sql.Open&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;With the general structure in place, we can start implementing the &lt;code&gt;WithinTransaction&lt;&#x2F;code&gt; logic. As we expect it, its role will be to manage the transaction and execute the provided callback within this context.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; txFunc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;BeginTx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; fmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;failed to begin transaction: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%w&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  txCtx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; txToContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; txFunc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;txCtx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Rollback&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Commit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; fmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;failed to commit transaction: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%w&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This implementation already deals with most of the workflow: the transaction is started with &lt;code&gt;BeginTx&lt;&#x2F;code&gt;, the &lt;code&gt;txFunc&lt;&#x2F;code&gt; callback is then executed, and the transaction is either &lt;code&gt;Commit&lt;&#x2F;code&gt;ted or &lt;code&gt;Rollback&lt;&#x2F;code&gt;ed depending on the callback result.&lt;&#x2F;p&gt;
&lt;p&gt;The actual magic happens at line 7, with the &lt;code&gt;txToContext&lt;&#x2F;code&gt; function call:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;txToContext&lt;&#x2F;code&gt; stores the transaction (an &lt;code&gt;*sql.Tx&lt;&#x2F;code&gt; instance) as a context key,&lt;&#x2F;li&gt;
&lt;li&gt;the context, enriched with the transaction, is passed to the callback function.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We can implement &lt;code&gt;txToContext&lt;&#x2F;code&gt; like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; txCtxKey&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; txToContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; pgx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithValue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; txCtxKey&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using a private struct type as a context key ensures nothing will conflict: this key can only be set by using &lt;code&gt;txCtxKey&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;At this point, the transactor logic is done. The actual &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;Thiht&#x2F;transactor@v1.1.0&#x2F;stdlib&quot;&gt;&lt;code&gt;transactor&#x2F;stdlib&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; implementation is a bit more complex because it can deal with nested transactions, but the logic is the same.&lt;&#x2F;p&gt;
&lt;p&gt;The only thing we miss is a way to actually use our transactor. When making our database queries, we must either check if our context contains a transaction, or use the DB connection directly.&lt;&#x2F;p&gt;
&lt;p&gt;To do so, we need a helper to give us the current transaction or connection from a context: the &lt;code&gt;DBGetter&lt;&#x2F;code&gt;. Let’s modify the &lt;code&gt;NewTransactor&lt;&#x2F;code&gt; constructor to give us a &lt;code&gt;DBGetter&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DBGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; NewTransactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;DB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DBGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; txFromContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; db&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;txFromContext&lt;&#x2F;code&gt; does the opposite of our previous &lt;code&gt;txToContext&lt;&#x2F;code&gt; function and is implemented as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; txFromContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; pgx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;txCtxKey&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{})&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;pgx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Tx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;DB&lt;&#x2F;code&gt; is simply an interface defining the common methods between &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;database&#x2F;sql#DB&quot;&gt;&lt;code&gt;*sql.DB&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;database&#x2F;sql#Tx&quot;&gt;&lt;code&gt;*sql.Tx&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, so that we can use a DB handler or a transaction indistinctly:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  ExecContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; args&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  PrepareContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Stmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  QueryContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; args&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Rows&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  QueryRowContext&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; args&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Row&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;DBGetter&lt;&#x2F;code&gt; we define will always return the initial &lt;code&gt;*sql.DB&lt;&#x2F;code&gt; handler by default, even if the context is completely empty (eg. &lt;code&gt;context.Background()&lt;&#x2F;code&gt; or &lt;code&gt;nil&lt;&#x2F;code&gt;), which makes it safe to use anywhere. The only way it can return a transaction is if it’s called inside a &lt;code&gt;WithinTransaction&lt;&#x2F;code&gt; block, as part of the &lt;code&gt;txFunc&lt;&#x2F;code&gt; callback we defined earlier.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;These changes conclude the transactor implementation. As you’ll see in the examples below, the key for it to work as intended is to &lt;strong&gt;always use the &lt;code&gt;DBGetter&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; to make database queries, never the &lt;code&gt;*sql.DB&lt;&#x2F;code&gt; directly. This is the only way that these functions will know to use an active transaction.&lt;&#x2F;p&gt;
&lt;p&gt;The following code is an example implementation of the &lt;code&gt;balanceStore&lt;&#x2F;code&gt; described at the beginning of this article, making use of the &lt;code&gt;DBGetter&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;	dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; DBGetter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; GetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;QueryRow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;SELECT amount FROM balances WHERE id = $1 FOR UPDATE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Scan&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; SetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Exec&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;UPDATE balances SET amount = $1 WHERE id = $2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; amount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; account&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; sql&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;lt;driver&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&amp;lt;dsn&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;NewTransactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;db&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; dbGetter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; transactor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;WithinTransaction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;GetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;account-1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;balanceStore&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;SetBalance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;account-1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; balance&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;	  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;	    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; ❌ Transaction rollbacked&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; ✅ Transaction committed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Using the context to pass information is sometimes controversial in the Go community, but in this case I feel the benefits vastly outweigh the cons. In fact, after using transactors for almost a full year in various situations, I&#x27;d say there isn&#x27;t anything that would make me go back to an alternative method for managing transactions.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, that’s it for today! I hoped you enjoyed this article, and if you did, I encourage you to give my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;transactor&quot;&gt;transactor&lt;&#x2F;a&gt; library a try in one of your projects, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht&#x2F;transactor&#x2F;stargazers&quot;&gt;maybe ⭐ it on GitHub&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Writing &amp; Testing a Paginated API Iterator in Go</title>
        <published>2024-12-19T00:00:00+00:00</published>
        <updated>2024-12-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/writing-testing-a-paginated-api-iterator/"/>
        <id>https://blog.thibaut-rousseau.com/blog/writing-testing-a-paginated-api-iterator/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/writing-testing-a-paginated-api-iterator/">&lt;p&gt;&lt;strong&gt;Go 1.23&lt;&#x2F;strong&gt;, amongst &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tip.golang.org&#x2F;doc&#x2F;go1.23&quot;&gt;other features&lt;&#x2F;a&gt;, brought &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;iter&quot;&gt;Iterators&lt;&#x2F;a&gt; to the standard library.&lt;&#x2F;p&gt;
&lt;p&gt;Iterators are basically a way to make the &lt;code&gt;range&lt;&#x2F;code&gt; operator work on functions implementing a specific interface. This lets you write code like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; myIterator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The main difference with using &lt;code&gt;range&lt;&#x2F;code&gt; over a slice or a map is that an iterator can fetch data lazily. I doesn’t need to fetch all the data at once before writing the loop. This comes really handy for consuming paginated APIs: we can write an iterator abstracting the pagination logic, making the code more readable and reusable.&lt;&#x2F;p&gt;
&lt;p&gt;In this article I’ll show you how to &lt;strong&gt;write a custom iterator&lt;&#x2F;strong&gt; for consuming a paginated HTTP API (we’ll use GitHub’s API as an example), and how to &lt;strong&gt;test it&lt;&#x2F;strong&gt; properly by leveraging &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;iter#hdr-Pulling_Values&quot;&gt;Pull Iterators&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Note that this article will not discuss the design of iterators in Go, we’ll just see how to use and work with them. For more information on iterators, I recommend these articles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;eli.thegreenplace.net&#x2F;2024&#x2F;ranging-over-functions-in-go-123&#x2F;&quot;&gt;Ranging over functions in Go 1.23&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;blog&#x2F;range-functions&quot;&gt;Range Over Function Types&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;writing-an-iterator&quot;&gt;Writing an Iterator&lt;&#x2F;h2&gt;
&lt;p&gt;Iterators can return up to two values. They must implement one of these signatures:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;iter#Seq&quot;&gt;&lt;code&gt;iter.Seq&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (&lt;code&gt;func(yield func(V) bool&lt;&#x2F;code&gt;): iterators over sequences of 1 value&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;iter#Seq2&quot;&gt;&lt;code&gt;iter.Seq2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (&lt;code&gt;func(yield func(K, V) bool&lt;&#x2F;code&gt;): iterators over sequences of 2 values&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;func(yield func() bool)&lt;&#x2F;code&gt;: iterators over sequence of… no value :)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For iterators working over remote resources like APIs, the emerging idiom is to use the second value for error handling. In practice, using our iterator will look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; IterateResources is a function returning an iter.Seq2[K, error]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; IterateResources&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; apiClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;        &#x2F;&#x2F; handle error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; use resource&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I noticed a few naming conventions for functions returning an iterator:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IterateResources&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IterResources&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ResourcesSeq&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I’m not sure yet which is the more common, but I went with &lt;code&gt;Iterate&lt;&#x2F;code&gt; in this article as it feels clearer.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We’ll implement an iterator looking like the above using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;fr&#x2F;rest&#x2F;repos&#x2F;repos?apiVersion=2022-11-28#list-repositories-for-a-user&quot;&gt;GitHub API to list the repositories of a user&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I chose this API for 3 reasons:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;it&#x27;s public and doesn&#x27;t require authentication. You can give it a try in a terminal:&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;https:&#x2F;&#x2F;api.github.com&#x2F;users&#x2F;thiht&#x2F;repos?page=1&amp;amp;per_page=5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;it&#x27;s paginated, so it&#x27;s a good use-case for an iterator,&lt;&#x2F;li&gt;
&lt;li&gt;the Go module &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;google&#x2F;go-github&#x2F;v67@v67.0.0&quot;&gt;google&#x2F;go-github&lt;&#x2F;a&gt; is readily available to interact with the GitHub API.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;With &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;google&#x2F;go-github&#x2F;v67@v67.0.0&quot;&gt;google&#x2F;go-github&lt;&#x2F;a&gt;, we’ll use the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;google&#x2F;go-github&#x2F;v67@v67.0.0&#x2F;github#RepositoriesService.ListByUser&quot;&gt;RepositoriesService.ListByUser&lt;&#x2F;a&gt; method. As a starting point, let’s write a version of the code listing all &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Thiht?tab=repositories&quot;&gt;my repositories&lt;&#x2F;a&gt;, without an iterator.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;package&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github.com&#x2F;google&#x2F;go-github&#x2F;v67&#x2F;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;NewClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;    1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      PerPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repositories&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;      panic&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;      println&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The pagination parameters are passed via &lt;code&gt;ListOptions&lt;&#x2F;code&gt;, and the next page to fetch is retrieved at each loop from the &lt;code&gt;resp&lt;&#x2F;code&gt; result. I set the pagination settings to list the repositories 5 by 5 so that we get a chance to see the pagination in action.&lt;&#x2F;p&gt;
&lt;p&gt;This code works fine, but it forces us to mix the pagination logic (checking the &lt;code&gt;NextPage&lt;&#x2F;code&gt; value and updating &lt;code&gt;opts.Page&lt;&#x2F;code&gt;) with our business logic (printing the repository name). It also suffers from a lack of standardization: any API you use will be different. Not only REST APIs, but also filesystem APIs, custom collections, or whatever. Iterators will help us abstract anything related to the pagination and focus on our own logic.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s now rewrite the same code with an iterator:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;package&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github.com&#x2F;google&#x2F;go-github&#x2F;v67&#x2F;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; 1. Iterator usage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;NewClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repositories&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  ) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;      panic&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;    println&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; 2. Iterator implementation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; RepositoryLister&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;  opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Seq2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; 2.1. Initialization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; = &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;PerPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;PerPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    &#x2F;&#x2F; 2.2. Pagination loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;        yield&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;          return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; RepositoryLister&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;  ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;    ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;    opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  ) ([]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, the iterator version is slightly more verbose, but it&#x27;s more reusable and has the benefit of isolating the pagination logic from the rest of the code. Keep in mind in real life projects you’ll modify the business logic of the loop more often than you’ll modify the iterator itself, so it makes sense to take a bit of time writing an iterator to get simpler business code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;IterateRepositoriesByUser&lt;&#x2F;code&gt; is not an iterator itself, but a function returning an iterator. This lets us pass the parameters that will be available in the scope of the iterator: the context, the GitHub client, the target user, and the additional options.&lt;&#x2F;p&gt;
&lt;p&gt;I declared a &lt;code&gt;RepositoryLister&lt;&#x2F;code&gt; interface to make it easier to test the iterator, we’ll come back to it in the next part.&lt;&#x2F;p&gt;
&lt;p&gt;The iterator consists of these steps:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2.1:&lt;&#x2F;strong&gt; Initialization of the pagination params before calling the API: the pagination starts at page 1 on the GitHub API,&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;2.2:&lt;&#x2F;strong&gt; Main loop listing the user’s repositories. Note that this is roughly the same code we had in the implementation without iterator: the pagination logic stays the same. The main difference is the use of &lt;code&gt;yield&lt;&#x2F;code&gt; to return our values and errors to &lt;code&gt;range&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;ListByUser&lt;&#x2F;code&gt; fails, yield the error and return: I decided to return unconditionally in case of failure, because I want the &lt;code&gt;range&lt;&#x2F;code&gt; to end if &lt;code&gt;ListByUser&lt;&#x2F;code&gt; fails.&lt;&#x2F;li&gt;
&lt;li&gt;If &lt;code&gt;ListByUser&lt;&#x2F;code&gt; succeeds, the repositories are yielded one by one.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As a reminder:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;yield&lt;&#x2F;code&gt; returns &lt;code&gt;true&lt;&#x2F;code&gt; if the &lt;code&gt;range&lt;&#x2F;code&gt; loop continues (if the &lt;code&gt;continue&lt;&#x2F;code&gt; keyword is used, or if the loop continues to the next iteration),&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;yield&lt;&#x2F;code&gt; returns &lt;code&gt;false&lt;&#x2F;code&gt; if the &lt;code&gt;range&lt;&#x2F;code&gt; loop stops (if &lt;code&gt;break&lt;&#x2F;code&gt; or &lt;code&gt;return&lt;&#x2F;code&gt; are used, or if the loop is interrupted).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;testing-the-iterator&quot;&gt;Testing the Iterator&lt;&#x2F;h2&gt;
&lt;p&gt;It can be a bit challenging to write tests for an iterator. In our tests we need to make sure that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the iterator contains the elements we expect, in the correct order,&lt;&#x2F;li&gt;
&lt;li&gt;the iterator doesn’t contain &lt;strong&gt;more&lt;&#x2F;strong&gt; elements than we expect.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;mocking-repositorylister&quot;&gt;Mocking &lt;code&gt;RepositoryLister&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Using a mock is not the only way to write this test, just my personal preference. As &lt;code&gt;github.NewClient&lt;&#x2F;code&gt; accepts an &lt;code&gt;*http.Client&lt;&#x2F;code&gt; as a parameter, we could instead use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;net&#x2F;http&#x2F;httptest&quot;&gt;&lt;code&gt;net&#x2F;http&#x2F;httptest&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to control the HTTP calls and their responses.&lt;&#x2F;p&gt;
&lt;p&gt;In the above example, we used an interface &lt;code&gt;RepositoryLister&lt;&#x2F;code&gt; to abstract the GitHub API client. Thanks to this abstraction, we can mock the GitHub API client in our tests. We could use a mocking library like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;vektra.github.io&#x2F;mockery&#x2F;latest&#x2F;&quot;&gt;mockery&lt;&#x2F;a&gt; to generate a mock for this interface automatically, but I&#x27;ll write it manually for this example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github.com&#x2F;google&#x2F;go-github&#x2F;v67&#x2F;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;     *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;       *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;        error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; newRepositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  mock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt; calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;mock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;      t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; unfulfilled calls to ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;mock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;mock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;r &lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) ([]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Helper&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;no result registered for ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected page: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; r&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This mock lets you register the expected calls to &lt;code&gt;ListByUser&lt;&#x2F;code&gt; and the results you want to return.
It can be used as follows, in place of a &lt;code&gt;RepositoryLister&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; Test_repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  mockClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; newRepositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; &#x2F;&#x2F; First call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt; &#x2F;&#x2F; Second call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;        fmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;an error occurred&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; mockClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected error &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected number of repositories: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected repository name: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%q&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%q&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected next page: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; mockClient&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;ListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;, &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;RepositoryListByUserOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ListOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;Page&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;expected error, got nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; An additional call to ListByUser will fail because there are no more results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;  &#x2F;&#x2F; mockClient.ListByUser(context.Background(), &amp;quot;thiht&amp;quot;, nil)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;writing-tests-for-the-sequence&quot;&gt;Writing tests for the sequence&lt;&#x2F;h3&gt;
&lt;p&gt;To test an iterator, I find it easier to first write down the expected sequence of values it returns. To do so, we can start by defining a type to represent the 2 values returned by an iteration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;    err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way we’ll be able to declare an expected sequence for a test:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Before writing our test, let’s setup our GitHub client mock with the expected responses to match this expected sequence:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;  calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;        {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;      resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our &lt;code&gt;repositoryListerMock&lt;&#x2F;code&gt; implements ListByUser, will return 2 repositories on the first page, and signal there’s no next page to fetch.&lt;&#x2F;p&gt;
&lt;p&gt;With all of this setup, we can finally test the iterator itself. The first trick here is to convert our iterator to a &lt;strong&gt;pull iterator&lt;&#x2F;strong&gt; to get finer control over the iteration sequence:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; 1. Initialize the iterator&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Pull2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; 2. Iterate and compare to the expected sequence&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected end of iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;DeepEqual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected repository: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected error: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;&#x2F;&#x2F; 3. Ensure the iterator is empty&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;  t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The actual testing consists of 3 parts:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;First, the iterator is initialized by calling &lt;code&gt;IterateRepositoriesByUser&lt;&#x2F;code&gt; with its expected parameters, including the mock client we created previously. We call &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;iter#Pull2&quot;&gt;&lt;code&gt;iter.Pull2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to convert the iterator to a push iterator, which gives us 2 new variables: &lt;code&gt;next&lt;&#x2F;code&gt; and &lt;code&gt;stop&lt;&#x2F;code&gt;. &lt;code&gt;next&lt;&#x2F;code&gt; will give us the next values in the iterator, and a boolean indicating whether it still contained values.&lt;&#x2F;li&gt;
&lt;li&gt;Then, we loop on the &lt;code&gt;expectedIterations&lt;&#x2F;code&gt;. That’s the second trick, we don’t loop directly on the iterator but instead on the sequence we expect. This lets us check all the values we expect one by one.
&lt;ul&gt;
&lt;li&gt;The first action in the loop is to call &lt;code&gt;next&lt;&#x2F;code&gt; to iterate. If the &lt;code&gt;ok&lt;&#x2F;code&gt; value returned by the iterator is &lt;code&gt;false&lt;&#x2F;code&gt; it means we expected more values than the iterator gave us, so the test fails.&lt;&#x2F;li&gt;
&lt;li&gt;Then, we can simply check that the returned &lt;code&gt;*github.Repository&lt;&#x2F;code&gt; and &lt;code&gt;error&lt;&#x2F;code&gt; are the ones we expected.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Finally we need to call &lt;code&gt;next&lt;&#x2F;code&gt; one last time to ensure the iterator is empty. If the &lt;code&gt;ok&lt;&#x2F;code&gt; value is &lt;code&gt;true&lt;&#x2F;code&gt;, it means the iterator contains more values than we expected. The test fails, and we need to rework our &lt;code&gt;expectedSequence&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This approach makes it easy to test all the possible cases for this iterator. The below examples show how to write a few additional tests, such as an iterator calling multiple pages of results, or an iterator returning an unexpected error.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; TestIterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;	type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;		repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;		err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;  error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;	t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;1 page of repositories&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;						{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;						{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;					}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Pull2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected end of iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;DeepEqual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected repository: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected error: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;	t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;2 pages of repositories&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;						{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;					}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;						{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;					}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;FullName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;example2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)}}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Pull2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected end of iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;DeepEqual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected repository: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected error: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;	t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;api error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		clientErr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; fmt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;an error occurred&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;        clientErr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; clientErr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Pull2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expectedIterations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected end of iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if !&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;reflect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;DeepEqual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected repository: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%+v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;			if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;				t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected error: got &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;, want &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;	t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;no repositories&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;repositoryListerMock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;			calls&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;callListByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					expectPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					repos&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;      []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;					resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:       &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;github&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7DCFFF;&quot;&gt;NextPage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;				}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;			}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Pull2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;IterateRepositoriesByUser&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;thiht&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;		t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt; next&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; ok&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;			t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;unexpected iteration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;	})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>TDD is a personal practice</title>
        <published>2023-12-18T00:00:00+00:00</published>
        <updated>2023-12-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/tdd-is-a-personal-practice/"/>
        <id>https://blog.thibaut-rousseau.com/blog/tdd-is-a-personal-practice/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/tdd-is-a-personal-practice/">&lt;p&gt;I know TDD. I know what real TDD is. I know how to do it right, whatever that means depending on the TDD practitioner.
I still don’t like this practice, and rarely use it, except in 2 situations:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I’m fixing a bug in an existing code base: in this case I’ll write a test first to reproduce and isolate the bug, and then fix it and refactor if needed&lt;&#x2F;li&gt;
&lt;li&gt;I’m adding a new use case to an existing feature, and will treat the lack of existence of this new case as a bug, see 1.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I don’t ever, ever, EVER use TDD to write new features from scratch. It doesn’t work for me. It doesn’t match my mental model. It doesn’t help me go faster, doesn’t make me produce better code, and doesn’t make me write more, or more useful tests. I don&#x27;t enjoy it and it doesn&#x27;t provide me with any kind of satisfaction.&lt;&#x2F;p&gt;
&lt;p&gt;I still have a personal methodology, but it’s not TDD. I still strive to write good test and maintain good coverage, but not doing TDD.&lt;&#x2F;p&gt;
&lt;p&gt;TDD should not be forced upon developers who don’t want to follow it, in the same way a specific IDE should not be forced upon a developer. TDD is a tool, not a goal in itself. The shared goal is to have a well tested code base that is as safe as possible from regressions. How developers achieve that doesn’t matter.&lt;&#x2F;p&gt;
&lt;p&gt;TDD should not be conflated as &quot;writing tests&quot;. I often see the rhetoric that, if you don’t do TDD, then you don’t write tests. If I showed you a code base with tests, there would be no way for you to know if they’ve been written in TDD or not.&lt;&#x2F;p&gt;
&lt;p&gt;TDD is not a team practice. Writing tests is a team practice. Code review is a team practice. Automated CI is a team practice. Whether a developer does or does not do TDD has no impact on the rest of the team. I could tell you I&#x27;m doing TDD if it pleases you, and you&#x27;d have no way to know that I don&#x27;t, micro-managing set aside.&lt;&#x2F;p&gt;
&lt;p&gt;If in TDD you trust, don’t proselytize it. TDD is a personal practice.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Shell Scripts Matter</title>
        <published>2017-12-03T00:00:00+00:00</published>
        <updated>2017-12-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/shell-scripts-matter/"/>
        <id>https://blog.thibaut-rousseau.com/blog/shell-scripts-matter/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/shell-scripts-matter/">&lt;img class=&quot;mx-auto&quot; src=&quot;.&#x2F;bash-logo.png&quot; alt=&quot;Bash logo&quot;&gt;
&lt;p&gt;The shell is an odd beast. Although it goes against every current trend in software engineering (strong typing, compile checks over runtime checks, ...), shell scripts are here to stay, and still constitute an important part of every developer&#x27;s life.&lt;&#x2F;p&gt;
&lt;p&gt;The weird thing about shell scripts is that even strong advocates of good practices gladly forget all they know when it comes to shell scripting.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Versioning? Why bother, it&#x27;s disposable code.&lt;&#x2F;p&gt;
&lt;p&gt;Code quality? That&#x27;s just a shell script, it&#x27;s garbage anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Testing? Nah. There aren&#x27;t any decent tools for that.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Wrong, wrong, and wrong. Shell scripts have value. &lt;strong&gt;Everything you do for real code should be done for non trivial shell scripts&lt;&#x2F;strong&gt;, even for a one-time script. That includes versioning, code reviews, continuous integration, static code analysis, and testing.&lt;&#x2F;p&gt;
&lt;p&gt;Here is a summary of everything that can, and should be done when writing shell scripts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; This article will use Bash as a reference shell. Most of the content can be transposed to other POSIX compliant shells.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;keep-your-scripts-in-version-control&quot;&gt;Keep your scripts in version control&lt;&#x2F;h2&gt;
&lt;p&gt;Keeping shell scripts under version control has multiple advantages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It constitutes a library. Shell scripts can be hard to write. If there&#x27;s a reference for something difficult somewhere, your coworkers will thank you when they need it. &lt;strong&gt;You should setup a &quot;shell-scripts&quot; repository&lt;&#x2F;strong&gt; somewhere as soon as possible.&lt;&#x2F;li&gt;
&lt;li&gt;They can be properly reviewed. Making mistakes is easy with shell scripts, and they can be very damaging. &lt;strong&gt;Code review should be mandatory for shell scripts&lt;&#x2F;strong&gt;, as for any other piece of code.&lt;&#x2F;li&gt;
&lt;li&gt;They can be improved. I won&#x27;t explain to you what version control is. But with shell scripts versioned, it&#x27;s easy to improve them regularly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Please, from now on, &lt;strong&gt;version all your shell scripts&lt;&#x2F;strong&gt; before running them. &lt;strong&gt;Have someone reviewing your scripts in priority&lt;&#x2F;strong&gt; before executing them in production. It&#x27;s not a waste of your coworkers&#x27; time, it&#x27;s a time saver for the team.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;improve-the-quality-of-your-scripts-with-shellcheck&quot;&gt;Improve the quality of your scripts with ShellCheck&lt;&#x2F;h2&gt;
&lt;p&gt;Although you can check the syntactic validity of your scripts with the command &lt;code&gt;bash -n&lt;&#x2F;code&gt;, much powerful tools exist.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.shellcheck.net&#x2F;&quot;&gt;ShellCheck&lt;&#x2F;a&gt; is a static code analysis tool for shell scripts. It&#x27;s really an awesome tool which will help you improve your skills as you use it. &lt;strong&gt;So do use it&lt;&#x2F;strong&gt;. You can &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck#installing&quot;&gt;install it globally on your machine&lt;&#x2F;a&gt;, use it in your &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck#travis-ci-setup&quot;&gt;continuous integration&lt;&#x2F;a&gt;, and it even &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck#in-your-editor&quot;&gt;integrates perfectly with most major editors&lt;&#x2F;a&gt;. There really are no downsides to using ShellCheck and it can save you from yourself.&lt;&#x2F;p&gt;
&lt;p&gt;If Steam had used ShellCheck in 2015, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;linux.slashdot.org&#x2F;story&#x2F;15&#x2F;01&#x2F;16&#x2F;1429201&#x2F;steam-for-linux-bug-wipes-out-all-of-a-users-files&quot;&gt;this line would never have made it to production&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;rm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -rf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$STEAMROOT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code violates the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck&#x2F;wiki&#x2F;SC2115&quot;&gt;SC2115 rule&lt;&#x2F;a&gt; from ShellCheck.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;use-bash-unofficial-strict-mode&quot;&gt;Use Bash unofficial strict mode&lt;&#x2F;h2&gt;
&lt;p&gt;The unofficial strict mode comes from Aaron Maxwell&#x27;s article &quot;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redsymbol.net&#x2F;articles&#x2F;unofficial-bash-strict-mode&#x2F;&quot;&gt;Use the Unofficial Bash Strict Mode (Unless You Looove Debugging)&lt;&#x2F;a&gt;&quot;. He suggests to start every Bash script with the following lines:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -euo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;IFS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=$&amp;#39;\n\t&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set -e&lt;&#x2F;code&gt; will exit the script if any command returns a non-zero status code. To prevent the option from triggering on commands returning a non-zero status code even when no error occurred, there are two solutions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;using the &lt;code&gt;|| true&lt;&#x2F;code&gt; pattern:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;command_returning_non_zero&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;temporary disabling the option:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; +e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;command_returning_non_zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set -u&lt;&#x2F;code&gt; will prevent using an undefined variable. In the case of undefined positional parameters (&lt;code&gt;$1&lt;&#x2F;code&gt;, &lt;code&gt;$2&lt;&#x2F;code&gt;, ...), you can give them a default value with the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;html_node&#x2F;Shell-Parameter-Expansion.html&quot;&gt;parameter expansion&lt;&#x2F;a&gt; construct:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;my_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;${1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:-&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;set -o pipefail&lt;&#x2F;code&gt; will force pipelines to fail on the first non-zero status code.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IFS=$&#x27;\n\t&#x27;&lt;&#x2F;code&gt; makes iterations and splitting less surprising, in the case of loops mostly. The default for this variable is usually &lt;code&gt;IFS=$&#x27; \n\t&#x27;&lt;&#x2F;code&gt; but the space as a separator often gives confusing results.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Read the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redsymbol.net&#x2F;articles&#x2F;unofficial-bash-strict-mode&#x2F;&quot;&gt;original article&lt;&#x2F;a&gt; for more details and &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redsymbol.net&#x2F;articles&#x2F;unofficial-bash-strict-mode&#x2F;#issues-and-solutions&quot;&gt;solutions for common challenges when using the strict mode&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;The unofficial strict mode is more intrusive than what we&#x27;ve seen before and can be hard to deal with, but it&#x27;s worth it in the long run. Take the time to try it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;do-some-cleanup&quot;&gt;Do some cleanup!&lt;&#x2F;h2&gt;
&lt;p&gt;When scripts are interrupted, either because of a user&#x27;s action or because something bad occurred, most shell scripts don&#x27;t clean up their mess. In the worst case, they might not restart services they had to temporarily disable. It&#x27;s a shame given how easy it is to perform some cleanup and error catching with the &lt;code&gt;trap&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;Once again, in &quot;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redsymbol.net&#x2F;articles&#x2F;bash-exit-traps&#x2F;&quot;&gt;How &quot;Exit Traps&quot; Can Make Your Bash Scripts Way More Robust And Reliable&lt;&#x2F;a&gt;&quot;, Aaron Maxwell gives some great advice.&lt;&#x2F;p&gt;
&lt;p&gt;Always add the following in your shell scripts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;trap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; cleanup EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;trap&lt;&#x2F;code&gt; command will execute the &lt;code&gt;cleanup&lt;&#x2F;code&gt; function as soon as the script exits. In this function you could remove temporary files, restart services, or whatever is relevant to your script.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;test-your-scripts-with-shunit2&quot;&gt;Test your scripts with shUnit2&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kward&#x2F;shunit2&quot;&gt;shUnit2&lt;&#x2F;a&gt; is a unit testing framework for shell scripts. It&#x27;s inspired by JUnit. It&#x27;s available in the standard repositories so you can install it with &lt;code&gt;apt-get install shunit2&lt;&#x2F;code&gt; on an Ubuntu-based distro.&lt;&#x2F;p&gt;
&lt;p&gt;shUnit2 consists of a shell script you can &lt;code&gt;source&lt;&#x2F;code&gt; in your test file. To use it, there are multiple approaches. In order not to clutter the main script, I prefer writing the tests in a separate file. This means I&#x27;ll have a &lt;code&gt;script.sh&lt;&#x2F;code&gt; file and a &lt;code&gt;test_script.sh&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;Below is an example for a script offering a function to add two numbers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;add.sh&lt;&#x2F;code&gt; must have the following structure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; $(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; + b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; )&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; [[ &amp;quot;${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;BASH_SOURCE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;}&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; ]];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Main code of the script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; $1 $2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[[ &quot;${BASH_SOURCE[0]}&quot; = &quot;$0&quot; ]]&lt;&#x2F;code&gt; test is used to execute the main code only when the script is executed directly, not &lt;code&gt;source&lt;&#x2F;code&gt;d.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;test_add.sh&lt;&#x2F;code&gt; will look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; .&#x2F;add.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;test_add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    actual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;add&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 5 8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    assertEquals&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$expected&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$actual&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; shunit2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;First, the test file &lt;code&gt;source&lt;&#x2F;code&gt;s the main file &lt;code&gt;add.sh&lt;&#x2F;code&gt; (in Bash, &lt;code&gt;.&lt;&#x2F;code&gt; is an alias to &lt;code&gt;source&lt;&#x2F;code&gt;). The functions it declares are then available in the test script.&lt;&#x2F;p&gt;
&lt;p&gt;The actual tests are simple functions with a name starting by &lt;code&gt;test&lt;&#x2F;code&gt;. At the end, the globally installed &lt;code&gt;shunit2&lt;&#x2F;code&gt; is &lt;code&gt;source&lt;&#x2F;code&gt;d and performs its &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ssb.stsci.edu&#x2F;testing&#x2F;shunit2&#x2F;shunit2.html#quickstart&quot;&gt;magic&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The test file can then be executed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ bash test_add.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test_add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Ran 1 test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The details of what shUnit2 can do are explained in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;ssb.stsci.edu&#x2F;testing&#x2F;shunit2&#x2F;shunit2.html#function-reference&quot;&gt;its documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There are alternatives to shUnit2, such as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sstephenson&#x2F;bats&quot;&gt;Bats&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bmizerany.github.io&#x2F;roundup&#x2F;&quot;&gt;Roundup&lt;&#x2F;a&gt; but I didn&#x27;t have a chance to use them yet. Their usage should be relatively similar though. The point of this section is that &lt;strong&gt;testing shell scripts is doable and should be done&lt;&#x2F;strong&gt;, whatever solution you choose in the end.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;log-what-your-script-is-doing&quot;&gt;Log what your script is doing&lt;&#x2F;h2&gt;
&lt;p&gt;In the past, I made the mistake of not logging anything. I liked running a script and seeing it work magically without anything ugly showing in the console. I was wrong, because when something doesn&#x27;t work as expected, it becomes impossible to know what happened. Running a script is not supposed to feel like magic, it must be somewhat verbose and understandable. For that, please &lt;strong&gt;log as much as possible in your scripts&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For this purpose, I usually add the following lines in my scripts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;readonly&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()    {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[INFO]    &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;warning&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[WARNING] &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()   {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[ERROR]   &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()   {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[FATAL]   &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This tiny logging framework allows to easily keep track of whatever happens during the script execution. Logging becomes as simple as writing &lt;code&gt;info &quot;Executing this and that...&quot;&lt;&#x2F;code&gt;. Then it&#x27;s easy to &lt;code&gt;grep&lt;&#x2F;code&gt; on the log file to find something specific. Feel free to improve these functions as you need, with the date, the calling function name (with &lt;code&gt;$FUNCNAME&lt;&#x2F;code&gt;), etc.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t use the builtin &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man1&#x2F;logger.1.html&quot;&gt;&lt;code&gt;logger&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; because it requires special privileges to write to &lt;code&gt;&#x2F;var&#x2F;log&lt;&#x2F;code&gt; and I&#x27;m not fond of its usage. Writing to a log file in &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; is usually good enough. For &lt;code&gt;cron&lt;&#x2F;code&gt; scripts though you should probably investigate &lt;code&gt;logger&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Use the &lt;code&gt;-v&lt;&#x2F;code&gt; or &lt;code&gt;--verbose&lt;&#x2F;code&gt; of the commands you invoke as needed to improve the quality of your logging.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;learn-to-debug-your-scripts&quot;&gt;Learn to debug your scripts&lt;&#x2F;h2&gt;
&lt;p&gt;The easiest way to debug a shell script, besides logging, is to run it with &lt;code&gt;bash -x&lt;&#x2F;code&gt;. Another way is to use &lt;code&gt;set -x&lt;&#x2F;code&gt; inside the script. This option will make Bash print every command before its execution, replacing the variables with their real values. Used together with the unofficial strict mode, this method is useful to see what&#x27;s going on in a script with less risk to break the environment.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also worth knowing that a few debuggers for Bash exist, for example &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;bashdb.sourceforge.net&#x2F;bashdb.html&quot;&gt;bashdb&lt;&#x2F;a&gt;. bashdb works in the same way as gdb, and can be used to add breakpoints, switching to step by step execution, showing the value of variables, etc. You can learn how to use bashdb with the video &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=jbOQJDSTksA&quot;&gt;Using BashDB to Debug Your Shell Scripts &lt;&#x2F;a&gt;&quot;:&lt;&#x2F;p&gt;
&lt;div&gt;
  &lt;iframe
    class=&quot;block m-auto w-full max-w-xl aspect-video border-none&quot;
    src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;jbOQJDSTksA&quot;
    allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;document-your-scripts&quot;&gt;Document your scripts&lt;&#x2F;h2&gt;
&lt;p&gt;Any shell script should have a &lt;code&gt;--help&lt;&#x2F;code&gt; option. This doesn&#x27;t seem easy? It is, thanks to the following wizardry:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Usage: add &amp;lt;first number&amp;gt; &amp;lt;second number&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Compute the sum of two numbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;usage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    grep&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;^#&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -c4-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;expr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;.*--help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; usage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;usage&lt;&#x2F;code&gt; function will print every line starting with &lt;code&gt;#&#x2F;&lt;&#x2F;code&gt; comments, without this prefix.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;expr&lt;&#x2F;code&gt; command will check if the string resulting of the concatenation of all the parameters contains &lt;code&gt;--help&lt;&#x2F;code&gt;. If so, it will call &lt;code&gt;usage&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is definitely not the cleanest way to parse parameters, but this quick method ensures you will add a &lt;code&gt;--help&lt;&#x2F;code&gt; flag.&lt;&#x2F;p&gt;
&lt;p&gt;For the sake of good practices, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;14203146&#x2F;1544176&quot;&gt;this StackOverflow post&lt;&#x2F;a&gt; explains how to properly parse a script&#x27;s parameters using the &lt;code&gt;while&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;case&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;shift&lt;&#x2F;code&gt; construct.&lt;&#x2F;p&gt;
&lt;p&gt;To generate HTML documentation from your comments, you can also check &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;rtomayko.github.io&#x2F;shocco&#x2F;&quot;&gt;shocco.sh&lt;&#x2F;a&gt;, which inspired &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rtomayko&#x2F;shocco&#x2F;blob&#x2F;e4660e563559d5bd9acbca42b61115e72b54667f&#x2F;shocco.sh#L54-L57&quot;&gt;the above trick&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;random-advice&quot;&gt;Random advice&lt;&#x2F;h2&gt;
&lt;p&gt;The following is a list of random good practices I&#x27;ve learned the hard way. I&#x27;ll explain the rationale behind every advice as I go.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-bash-for-scripting&quot;&gt;Use Bash for scripting&lt;&#x2F;h3&gt;
&lt;p&gt;Use Bash by default, Sh if you have to. Try to forget about Ksh, Zsh or Fish unless there are really good reasons to use them. This choice not only ensures your script will work virtually everywhere, but also fosters comprehension of a script by the whole team. You don&#x27;t write production scripts for yourself.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-bashisms&quot;&gt;Use Bashisms&lt;&#x2F;h3&gt;
&lt;p&gt;If you use Bash, don&#x27;t half-use it. Use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;html_node&#x2F;Shell-Parameter-Expansion.html&quot;&gt;parameter expansion&lt;&#x2F;a&gt;. Use &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;tldp.org&#x2F;LDP&#x2F;abs&#x2F;html&#x2F;localvar.html&quot;&gt;local&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ss64.com&#x2F;bash&#x2F;readonly.html&quot;&gt;readonly&lt;&#x2F;a&gt; variables. Use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;html_node&#x2F;Bash-Conditional-Expressions.html&quot;&gt;improved conditional expressions&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;quote-your-variables&quot;&gt;Quote your variables&lt;&#x2F;h3&gt;
&lt;p&gt;Even if you know quoting is not required, it&#x27;s a good habit to always quote variables. The only exception is when you specifically want expansion to occur. More on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck&#x2F;wiki&#x2F;SC2086&quot;&gt;word splitting&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;name-your-parameters&quot;&gt;Name your parameters&lt;&#x2F;h3&gt;
&lt;p&gt;This goes without saying, but explicitly naming parameters (&lt;code&gt;$1&lt;&#x2F;code&gt;, &lt;code&gt;$2&lt;&#x2F;code&gt;, ...) makes the code self-documenting and helps readability. The parameter expansion of Bash is a great candidate for naming and assigning default values to positional parameters:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;my_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;${1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;:-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;use-subshells-as-a-way-to-control-what-s-in-your-global-scope&quot;&gt;Use subshells as a way to control what&#x27;s in your global scope&lt;&#x2F;h3&gt;
&lt;p&gt;An example is worth a thousand words:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; $var&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; $var&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; $var&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; $var&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;will print:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My main usage for this is when I need to temporarily modify &lt;code&gt;$IFS&lt;&#x2F;code&gt; (for iterating over simple CSV-like files for example) and reset it to its original value afterwards.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-a-template&quot;&gt;Use a template&lt;&#x2F;h3&gt;
&lt;p&gt;This script template summarizes every snippets shared along this article. I believe it&#x27;s a good basis for any kind of script.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -euo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;IFS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=$&amp;#39;\n\t&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Usage:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Description:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Examples:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F; Options:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;#&#x2F;   --help: Display this help message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;usage&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;^#&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;#39; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -c4-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;expr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;.*--help&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; &#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; usage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9D7CD8;font-style: italic;&quot;&gt;readonly&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;&#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()    {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[INFO]    &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;warning&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[WARNING] &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()   {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[ERROR]   &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;fatal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;()   {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;[FATAL]   &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F7768E;&quot;&gt;$*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt; tee&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt; -a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;$LOG_FILE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; &amp;gt;&amp;amp;2 ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt; exit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FF9E64;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; ;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #7AA2F7;&quot;&gt;cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Remove temporary files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Restart services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; [[ &amp;quot;${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C0CAF5;&quot;&gt;BASH_SOURCE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ABDF5;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;}&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E0AF68;&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DDFF;&quot;&gt;&amp;quot; ]];&lt;&#x2F;span&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #0DB9D7;&quot;&gt;    trap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECE6A;&quot;&gt; cleanup EXIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # Script goes here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #51597D;font-style: italic;&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #BB9AF7;&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;stay-informed&quot;&gt;Stay informed&lt;&#x2F;h3&gt;
&lt;p&gt;Shell scripting isn&#x27;t moving that much these days. It&#x27;s a great reason to read stuff about the topic, it makes it easy to keep up! Here are some interesting resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;man bash&lt;&#x2F;code&gt;, I bet almost none of you have read it, yet it&#x27;s a great source of information! And it&#x27;s not that hard to read, I promise.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;UnixToolTip&quot;&gt;@UnixTooltip&lt;&#x2F;a&gt; on Twitter, continuously gives tips and tricks.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;tagged&#x2F;bash?sort=votes&amp;amp;pageSize=15&quot;&gt;Most upvoted Bash questions on StackOverflow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;documentation&#x2F;bash&#x2F;topics&quot;&gt;Bash participative documentation on StackOverflow&lt;&#x2F;a&gt; has some interesting examples.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck&#x2F;wiki&quot;&gt;ShellCheck&#x27;s wiki&lt;&#x2F;a&gt; is a good resource to learn what not to do, and why.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;news&quot;&gt;Hacker News&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;&quot;&gt;&#x2F;r&#x2F;programming&lt;&#x2F;a&gt;, once in a while articles on this subject pop out.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I hope this article brought light on what was possible with shell scripting. The tools are there. You know the practices. Now it&#x27;s up to you to make scripting a delight to work with, for you and your team!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Learn to use screen, a terminal multiplexer</title>
        <published>2015-12-04T00:00:00+00:00</published>
        <updated>2015-12-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thibaut Rousseau
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.thibaut-rousseau.com/blog/screen-terminal-multiplexer/"/>
        <id>https://blog.thibaut-rousseau.com/blog/screen-terminal-multiplexer/</id>
        
        <content type="html" xml:base="https://blog.thibaut-rousseau.com/blog/screen-terminal-multiplexer/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;screen&#x2F;&quot;&gt;screen&lt;&#x2F;a&gt;, or GNU screen, is a terminal multiplexer. It allows to manage multiple terminal sessions within the same console. In a way, it does the same thing as modern terminal emulators such as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnometerminator.blogspot.com&#x2F;&quot;&gt;Terminator&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.enlightenment.org&#x2F;about-terminology&quot;&gt;Terminology&lt;&#x2F;a&gt; with their built-in tab system and layout management. The main benefit is that screen also works through an SSH connection: you will be able to use your screen knowledge and configuration on any machine supporting screen in the world!&lt;&#x2F;p&gt;
&lt;p&gt;screen has been around for almost 30 years so it&#x27;s pretty stable now. It is released under the GPL license.&lt;&#x2F;p&gt;
&lt;p&gt;The main issue I had when starting with screen was its relative difficulty when compared to simple terminal emulators. So &lt;strong&gt;I will make a tour of the most useful keyboard shortcuts for a practical use&lt;&#x2F;strong&gt;, and share with you my screen config. You can also jump directly to the &lt;a href=&quot;https:&#x2F;&#x2F;blog.thibaut-rousseau.com&#x2F;blog&#x2F;screen-terminal-multiplexer&#x2F;#cheatsheet-of-the-main-commands&quot;&gt;cheatsheet&lt;&#x2F;a&gt; if you want.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basic-usage&quot;&gt;Basic usage&lt;&#x2F;h2&gt;
&lt;p&gt;screen is not installed by default, so you need to install it first using your package manager.&lt;&#x2F;p&gt;
&lt;p&gt;To &lt;strong&gt;start screen&lt;&#x2F;strong&gt;, open a terminal and run the command &lt;code&gt;screen&lt;&#x2F;code&gt;. Not that hard, is it?&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re ready to start learning screen. Don&#x27;t worry, that&#x27;s only a few commands!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;window-management&quot;&gt;Window management&lt;&#x2F;h3&gt;
&lt;p&gt;Now you have opened screen, the first thing you need to know is how to &lt;strong&gt;create a new &quot;window&quot;&lt;&#x2F;strong&gt; (i.e. a new virtual terminal). To do so, press the keys &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt;, and then press &lt;code&gt;c&lt;&#x2F;code&gt;. The screen shortcuts all consist of &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; (called &quot;escape key&quot; or &quot;prefix&quot;) followed by another key. You now have two windows opened running in parallel, you can have vim in the first one, and a bash in the second one for example, and that&#x27;s what screen is all about.&lt;&#x2F;p&gt;
&lt;p&gt;You can &lt;strong&gt;visualize all the opened windows&lt;&#x2F;strong&gt; with &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&quot;&lt;&#x2F;code&gt;. This view allows you to navigate through your windows with the arrow keys, the 0-9 numbers and the enter key. This command is great because it gives you a global overview of your current session, I used it a lot at first.&lt;&#x2F;p&gt;
&lt;p&gt;But there are more ways to &lt;strong&gt;navigate through the windows&lt;&#x2F;strong&gt;! I personally use almost exclusively the commands &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;p&lt;&#x2F;code&gt; (&lt;strong&gt;p&lt;&#x2F;strong&gt;revious window) and  &lt;code&gt;Ctrl + a&lt;&#x2F;code&gt; &lt;code&gt;n&lt;&#x2F;code&gt; (&lt;strong&gt;n&lt;&#x2F;strong&gt;ext window). These shortcuts require to have your windows in mind though, but it comes with practice. And don&#x27;t forget &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&quot;&lt;&#x2F;code&gt; is here to rescue you in case of doubt. ;)&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also possible to jump to another window with the command &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;em&gt;&lt;code&gt;number&lt;&#x2F;code&gt;&lt;&#x2F;em&gt;, where &lt;em&gt;number&lt;&#x2F;em&gt; is a number between 0 and 9. This matches the &quot;Num&quot; column of the &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&quot;&lt;&#x2F;code&gt; view.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you can &lt;strong&gt;kill a window&lt;&#x2F;strong&gt; when you have no use for it anymore. To do so, just press &lt;code&gt;Ctrl+d&lt;&#x2F;code&gt; in the shell. There&#x27;s also a screen command with the &quot;same&quot; effect but it&#x27;s usually better to proceed this way. Note if you kill all the windows of a session, the session terminates.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Summary:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;c&lt;&#x2F;code&gt; to create a new window&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&quot;&lt;&#x2F;code&gt; to visualize the opened windows&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;p&lt;&#x2F;code&gt; and &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;n&lt;&#x2F;code&gt; to switch with the previous&#x2F;next window&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;em&gt;&lt;code&gt;number&lt;&#x2F;code&gt;&lt;&#x2F;em&gt; to switch to the window &lt;em&gt;number&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+d&lt;&#x2F;code&gt; to kill a window&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;session-management&quot;&gt;Session management&lt;&#x2F;h3&gt;
&lt;p&gt;Now you can manage your windows, it is time you learn how to manage your screen sessions.&lt;&#x2F;p&gt;
&lt;p&gt;You just learned you can terminate a session by killing all its windows, that&#x27;s a good start. We will now see how to &lt;strong&gt;exit a session without killing it&lt;&#x2F;strong&gt;. It means you&#x27;ll be able to manage multiple persistent sessions in parallel. This is called &quot;detaching&quot; a session. To be clear, a &lt;strong&gt;detached session&lt;&#x2F;strong&gt; is a session which is still active in background, but on which no one is connected. An &lt;strong&gt;attached session&lt;&#x2F;strong&gt; is a session which is active and currently used.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing I&#x27;ll ask you to do is to kill your current screen session if you haven&#x27;t done it already. You can then &lt;strong&gt;list all your screen sessions&lt;&#x2F;strong&gt; by running the command &lt;code&gt;screen -ls&lt;&#x2F;code&gt;. If all your sessions are closed, it should print something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;No Sockets found in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we&#x27;ll start a &lt;strong&gt;new session&lt;&#x2F;strong&gt;, but &lt;strong&gt;we&#x27;ll give it a name&lt;&#x2F;strong&gt; so that we can come back to it more easily later. Run the command &lt;code&gt;screen -S my_session&lt;&#x2F;code&gt;. If you run the command &lt;code&gt;screen -ls&lt;&#x2F;code&gt;, you should obtain something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There is a screen on:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10321.my_session        (Attached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 Socket in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since you&#x27;re connected to the session, it&#x27;s presented as &lt;strong&gt;attached&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now you&#x27;re connected to a session named &quot;my_session&quot;, you can &lt;strong&gt;detach it from the current terminal&lt;&#x2F;strong&gt; with the command &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;d&lt;&#x2F;code&gt;. This should result in a message like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[detached from 10321.my_session]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As usual, you can list the currently running sessions with &lt;code&gt;screen -ls&lt;&#x2F;code&gt;. This time, &quot;my_session&quot; should be listed as &lt;strong&gt;detached&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There is a screen on:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10321.my_session        (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 Socket in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I suggest you start and detach a few screen sessions to understand how it works. &lt;strong&gt;Be careful not to use the same session name twice&lt;&#x2F;strong&gt;, screen allows it but it can be more painful to resume a session if there are name conflicts.&lt;&#x2F;p&gt;
&lt;p&gt;With multiple screen sessions, the &lt;code&gt;screen -ls&lt;&#x2F;code&gt; gives something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There are screens on:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10474.downloads (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10427.work      (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10321.my_session        (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 Sockets in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If there aren&#x27;t any conflicts, you can &lt;strong&gt;resume a session&lt;&#x2F;strong&gt; simply with the command &lt;code&gt;screen -x session_name&lt;&#x2F;code&gt;. So for example if you run &lt;code&gt;screen -x my_session&lt;&#x2F;code&gt;, your session &quot;my_session&quot; will be resumed with the windows you opened before! And if you run &lt;code&gt;screen -ls&lt;&#x2F;code&gt;, it should appear as &lt;strong&gt;attached&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There are screens on:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10474.downloads (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10427.work      (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10321.my_session        (Attached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 Sockets in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A last useful thing you should know is how to &lt;strong&gt;kill a detached session without connecting to it&lt;&#x2F;strong&gt;. To do so, the command to run is a bit tricky: &lt;code&gt;screen -S session_name -X quit&lt;&#x2F;code&gt;. This means you pass the command &quot;quit&quot; to the session named &quot;session_name&quot;. It&#x27;s a bit hard to remember so I generally simply resume my session and kill all its windows one by one.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Summary:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;screen -ls&lt;&#x2F;code&gt; to list the sessions and their status&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;screen -S session_name&lt;&#x2F;code&gt; to start a session with a given name. The name
should be unique&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;d&lt;&#x2F;code&gt; to detach a session&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;screen -x session_name&lt;&#x2F;code&gt; to resume (reattach) a session knowing its name&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;screen -S session_name -X quit&lt;&#x2F;code&gt; to terminate a detached session&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;advanced-usage&quot;&gt;Advanced usage&lt;&#x2F;h2&gt;
&lt;p&gt;The hardest part is over! You have discovered screen and you know how to use it. All you need now is practice.&lt;&#x2F;p&gt;
&lt;p&gt;In this section, I&#x27;ll present a few interesting features of screen, but they&#x27;re definitely not necessary to use it, so feel free to come back and read this part later.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;layout-management&quot;&gt;Layout management&lt;&#x2F;h3&gt;
&lt;p&gt;In the introduction, I talked about how Terminator and Terminology can work as layout managers. The good news is screen also permits to do that. So to &lt;strong&gt;split horizontally&lt;&#x2F;strong&gt;, you can use the command &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;S&lt;&#x2F;code&gt;, and to &lt;strong&gt;split vertically&lt;&#x2F;strong&gt; you can use &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;|&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To &lt;strong&gt;switch to the next region&lt;&#x2F;strong&gt; (this is how the split panes are called), the command to use is &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;&#x2F;code&gt;. Each region behaves normally: you can run any command you have learned so far.&lt;&#x2F;p&gt;
&lt;p&gt;To &lt;strong&gt;close the current region&lt;&#x2F;strong&gt;, use &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;X&lt;&#x2F;code&gt;. If you work with a lot of panes, you can &lt;strong&gt;close them all but the current one&lt;&#x2F;strong&gt; with &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;Q&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Summary:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;S&lt;&#x2F;code&gt; to split horizontally&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;|&lt;&#x2F;code&gt; to split vertically&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;&#x2F;code&gt; to switch to the next region&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;X&lt;&#x2F;code&gt; to close the current region&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;Q&lt;&#x2F;code&gt; to close all the regions but the current one&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;work-with-the-buffer&quot;&gt;Work with the buffer&lt;&#x2F;h3&gt;
&lt;p&gt;To follow, I&#x27;ll talk about an important feature of screen: the copy mode, or scrollback mode.&lt;&#x2F;p&gt;
&lt;p&gt;To &lt;strong&gt;enter the copy mode&lt;&#x2F;strong&gt;, the command is either &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;&#x2F;code&gt; or &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;[&lt;&#x2F;code&gt;, choose your side. The copy mode allows you to &lt;strong&gt;navigate through the console buffer without using your mouse&lt;&#x2F;strong&gt;. Since you can&#x27;t use your wheel to scroll by default, this is the normal way to go back in the results. This mode lets you use some vim commands for the movements (arrow keys, &lt;code&gt;0&lt;&#x2F;code&gt;, &lt;code&gt;$&lt;&#x2F;code&gt;, &lt;code&gt;g&lt;&#x2F;code&gt;, &lt;code&gt;G&lt;&#x2F;code&gt;, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;You can &lt;strong&gt;copy some text&lt;&#x2F;strong&gt; (that&#x27;s what the mode is for!) by marking the beginning and the end of a section with the space bar. You can then &lt;strong&gt;paste it&lt;&#x2F;strong&gt; with &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;]&lt;&#x2F;code&gt;.  For more informations, check the &lt;code&gt;man screen&lt;&#x2F;code&gt; and look for &quot;copy&quot;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Summary:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;&#x2F;code&gt; or &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;[&lt;&#x2F;code&gt; to enter in copy mode&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Space&amp;gt;&lt;&#x2F;code&gt; to select and copy some text in copy mode&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;]&lt;&#x2F;code&gt; to paste the content of the buffer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;session-sharing&quot;&gt;Session sharing&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ll finish with a last screen feature I want you to know about: it allows to share a session between multiple users. When working on a remote server, this comes really handy.&lt;&#x2F;p&gt;
&lt;p&gt;So first, you have to start a session as usual. Then, we&#x27;ll use the command mode of screen to enable the multiuser mode and give the access right to some users. To &lt;strong&gt;enter the command mode&lt;&#x2F;strong&gt;, type &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt;. You can then &lt;strong&gt;enable the multiuser mode&lt;&#x2F;strong&gt; with the command &lt;strong&gt;multiuser on&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Then to &lt;strong&gt;add a specific user to the session&lt;&#x2F;strong&gt;, enter the command mode again with &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt; and type the command &lt;strong&gt;acladd &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; (ACL stands for &quot;Access Control List&quot;) with the name of the user you want to add instead of &lt;em&gt;username&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The user &lt;em&gt;username&lt;&#x2F;em&gt; is now able to &lt;strong&gt;join your session&lt;&#x2F;strong&gt; simply with the command &lt;code&gt;screen -x your_username&#x2F;session_name&lt;&#x2F;code&gt;. The session is completely shared, which means you can see what the other users do in real time and so can they.&lt;&#x2F;p&gt;
&lt;p&gt;When a session is shared with multiple users, it can be nice to &lt;strong&gt;know who is currently connected on it&lt;&#x2F;strong&gt;. You can have this info and more thanks to the command &lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;*&lt;&#x2F;code&gt;. The view shows a few useful informations, namely the window a user is currently using, or their permissions.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you can &lt;strong&gt;revoke the access rights of user&lt;&#x2F;strong&gt; with the command &lt;strong&gt;acldel &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt; in command mode. There&#x27;s more you can do to manage a shared session, but I won&#x27;t go into details, the man page covers everything. Now you have a basic understanding of screen, it should be easier to understand.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Summary:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt; to switch to command mode
&lt;ul&gt;
&lt;li&gt;&quot;multiuser on&quot; to enable the multiuser mode&lt;&#x2F;li&gt;
&lt;li&gt;&quot;acladd &lt;em&gt;username&lt;&#x2F;em&gt;&quot; to give the access rights to the user &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&quot;acldel &lt;em&gt;username&lt;&#x2F;em&gt;&quot; to remove the access rights to the user &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;screen -x owner&#x2F;session_name&lt;&#x2F;code&gt; to join a session started by another user&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;*&lt;&#x2F;code&gt; to list the other connections to a session&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;practical-tips&quot;&gt;Practical tips&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;automatically-list-the-screen-sessions&quot;&gt;Automatically list the screen sessions&lt;&#x2F;h3&gt;
&lt;p&gt;When I start my terminal, I like it to list the current screen sessions. To do so, I simply added the &lt;code&gt;screen -ls&lt;&#x2F;code&gt; command to my .bashrc. So now whenever I open a terminal, I&#x27;m welcomed with my screen status:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;There are screens on:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2927.my_screen3 (Attached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2882.my_screen2 (Attached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2840.my_screen1 (Detached)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 Sockets in &#x2F;var&#x2F;run&#x2F;screen&#x2F;S-thiht.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Not only is it really useful to have this status without asking for it, but it is also a good way to think about always using screen.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;good-aliases&quot;&gt;Good aliases&lt;&#x2F;h3&gt;
&lt;p&gt;As you&#x27;re now aware, screen uses a lot of options. I tried to keep only the most useful in this article but they&#x27;re still a pain to remember. A good way to remember them is to use aliases. I personally use the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;alias sn=&amp;#39;screen -S&amp;#39;  # sn for screen new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;alias sl=&amp;#39;screen -ls&amp;#39; # sl for screen list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;alias sr=&amp;#39;screen -x&amp;#39;  # sr for screen resume&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function sk() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # sk for screen kill&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    # function instead of alias because the order of the parameters matters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    screen -S &amp;quot;$1&amp;quot; -X quit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These aliases don&#x27;t conflict with anything standard and they&#x27;re really easier to remember and to type, so I strongly advise you to use them!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;custom-configuration&quot;&gt;Custom configuration&lt;&#x2F;h3&gt;
&lt;p&gt;screen can be customized in various ways through a .screenrc file, located in your home folder. One of the most useful tricks is the status bar.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;blog.thibaut-rousseau.com&#x2F;blog&#x2F;screen-terminal-multiplexer&#x2F;.&#x2F;screen-session-with-status-bar.png&quot; alt=&quot;screen session with a status bar&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t go through the configuration of screen in details (you can read &lt;code&gt;man screen&lt;&#x2F;code&gt; or other articles to learn more), but simply share my commented .screenrc with you:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B1D6; background-color: #1A1B26;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# enable the altscreen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# for example in vim, it allows to scroll with the mouse without&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &amp;quot;overflowing&amp;quot; on the terminal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# also it doesn&amp;#39;t &amp;quot;pollute&amp;quot; the terminal when you quit vim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;altscreen on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# automatically detach the session if the terminal is closed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;autodetach on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# larger command history&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;defscrollback 10000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# set the encoding of the windows to utf-8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;defutf8 on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# disable the startup message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;startup_message off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# allow to scroll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;termcapinfo xterm* ti@:te@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# disable the annoying visual bell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vbell off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# status bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %{= wk}: set the color to white on black&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %S: screen session name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %-w: previous windows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %{= kw}: set the color to black on white&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %n: current window number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %t: current window title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %{= wk}: set the color to white on black&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# %+w: next windows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;caption always &amp;quot;%{= wk}%S: %-w%{= kw}%n %t%{= wk}%+w&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note you can enable any of these options directly from screen&#x27;s command mode.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cheatsheet-of-the-main-commands&quot;&gt;Cheatsheet of the main commands&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;basic-usage-1&quot;&gt;Basic usage&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Start a session&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen -ls &lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;L&lt;&#x2F;strong&gt;i&lt;strong&gt;s&lt;&#x2F;strong&gt;t the sessions and their status&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen -S session_name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;S&lt;&#x2F;strong&gt;tart a session named &quot;session_name&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen -x session_name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Resume the session named &quot;session_name&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen -S session_name -X quit&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Terminate the session named &quot;session_name&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;c&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;C&lt;&#x2F;strong&gt;reate a new window&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;k&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;K&lt;&#x2F;strong&gt;ill the current window (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;End-of-transmission_character&quot;&gt;&lt;code&gt;Ctrl+d&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; does the same thing)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&quot;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;List the opened windows&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;p&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;n&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Go to the &lt;strong&gt;p&lt;&#x2F;strong&gt;revious&#x2F;&lt;strong&gt;n&lt;&#x2F;strong&gt;ext window&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;0&lt;&#x2F;code&gt;-&lt;code&gt;9&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Go to the window &lt;em&gt;n&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;d&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;D&lt;&#x2F;strong&gt;etach the screen session&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Enter the command mode&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h4 id=&quot;split-mode&quot;&gt;Split mode&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;&#x2F;th&gt;&lt;th&gt;Action&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;S&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;S&lt;&#x2F;strong&gt;plit horizontally&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; `&lt;&#x2F;td&gt;&lt;td&gt;`&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Go to the next region&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;X&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Close the current region&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;Q&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Close all the regions but the current one&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h4 id=&quot;copy-mode&quot;&gt;Copy mode&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;&#x2F;th&gt;&lt;th&gt;Action&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;[&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Enter the copy mode&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;lt;Space&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Mark a selection&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;]&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Paste the content of the buffer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h4 id=&quot;shared-session&quot;&gt;Shared session&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;&#x2F;th&gt;&lt;th&gt;Action&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt; &lt;code&gt;multiuser on&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Enable the multiuser mode&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt; &lt;code&gt;acladd username&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Give the access rights to &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;:&lt;&#x2F;code&gt; &lt;code&gt;acldel username&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Revoke the access rights to &lt;em&gt;username&lt;&#x2F;em&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl+a&lt;&#x2F;code&gt; &lt;code&gt;*&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;List the other connections to the session&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;screen -x owner&#x2F;session_name&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Join a session started by another user&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;screen is a powerful tool if you use the terminal a lot. Yet, it has some drawbacks, that can be pretty annoying. To list a few you &lt;strong&gt;will&lt;&#x2F;strong&gt; be confronted to if you really try to use it:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;bad UTF-8 support. There are a few configurations to make screen work fine with unicode, but it&#x27;s still a bit messy. I am not even sure there is a proper way to handle UTF-8 characters in the status bar...&lt;&#x2F;li&gt;
&lt;li&gt;insane status bar configuration. You can see it in the .screenrc I provided, crafting a neat status bar is really hard. It&#x27;s a shame given how useful they are!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Good news though, all these issues are allegedly solved with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tmux.github.io&#x2F;&quot;&gt;tmux&lt;&#x2F;a&gt;, another more recent terminal mutiplexer. I&#x27;ve only used it as a replacement of screen for a few days so I will wait a bit before reviewing it, but it&#x27;s very similar to screen in its usage, and I&#x27;m very satisfied with it so far.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
