Jekyll2021-07-19T13:14:51+01:00https://blog.myitcv.io/feed.xmlblog.myitcv.ioA largely Go-based blog
Paul JollyPortable CI/CD with pure Go GitHub Actions2020-02-04T00:00:00+00:002020-02-04T00:00:00+00:00https://blog.myitcv.io/2020/02/04/portable-ci-cd-with-pure-go-github-actions<p>I recently converted the <a href="https://github.com/govim/govim"><code class="language-plaintext highlighter-rouge">govim</code></a> project to use <a href="https://github.com/features/actions">GitHub
Actions</a>. The move away from <a href="https://travis-ci.org/">TravisCI</a> was largely
motivated by more generous concurrency limits (<a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#usage-limits">GitHub’s
20</a>
jobs vs TravisCI’s 5), faster job startup times, and solid cross-platform support. But there was also the promise of
making it easy to extend workflows with composable third-party actions. This post demonstrates how to write
cross-platform, pure Go GitHub actions that you can use in your workflows and share with others. But first we start by
motivating the real problem we are trying to solve.</p>
<!-- __JSON: gobin -m -run myitcv.io/cmd/egrunner -uid -gid ../_scripts/2020-02-04-portable-ci-cd-with-pure-go-github-actions/Dockerfile ../_scripts/2020-02-04-portable-ci-cd-with-pure-go-github-actions/script.sh # LONG ONLINE
### Wait, there's a problem with GitHub Actions?
Julien Renaux wrote a [blog post](https://julienrenaux.fr/2019/12/20/github-actions-security-risk/) that does a good job
of laying out one of the core problems with GitHub Actions. The story goes roughly like this:
* someone writes and open-sources an action that requires secret credentials, e.g. DockerHub access token
* lots of people start using the action via directives like `uses: good/action@v1` because it's well written and useful
* original author welcomes a new maintainer on board
* somehow existing action version tags get moved, pointing to malicious code that steals secrets (any maintainer can
update a branch or a tag)
Hence the specific advice is to use a commit hash to partially mitigate this risk:
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">That’s why you need to specify the exact version (action@sha1) you want to use, so further changes won’t impact you.</p>— Alain Hélaïli (@AlainHelaili) <a href="https://twitter.com/AlainHelaili/status/1205238489056501761?ref_src=twsrc%5Etfw">December 12, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
_It is somewhat unfortunate at best that this isn't the default advice in the official documentation; worth noting it
doesn't defend against the commit disappearing._
The problems don't stop there, because there is also the risk that transitive dependencies can do malicious things too:
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">There is also a risk that the transitive dependencies can do malicious things.<a href="https://t.co/juffjxwxIr">https://t.co/juffjxwxIr</a></p>— DrSensor👹 (@dr\_sensor) <a href="https://twitter.com/dr_sensor/status/1208098900747284480?ref_src=twsrc%5Etfw">December 20, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
On top of this, it's not made particularly clear to users that every action they use in their workflow is given implicit
access to an access token that has fairly [wide-ranging read-write access to the host
repository](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#permissions-for-the-github_token).
So we clearly have a software dependency problem here.
### Why Go?
[Russ Cox](https://twitter.com/_rsc) has [repeatedly](https://research.swtch.com/deps)
[written](https://twitter.com/_rsc/status/1088109141409837063) about "Our Software Dependency Problem." The basic
premise of those articles is that "software dependencies carry with them serious risks that are too often overlooked."
Whilst Russ' articles raise awareness of the risks and encourage more investigation of solutions (and I strongly
encourage you to read the article in full), the bottom line is that Go has a comprehensive solution to the major
problems outlined, via the [Go Module Mirror](https://proxy.golang.org/), [Index](https://index.golang.org/), and
[Checksum Database](https://sum.golang.org/), that ultimately results in the `go` command referencing an auditable
checksum database to authenticate modules. Coupled with the [minimum version
selection](https://research.swtch.com/vgo-mvs) property of Go modules, we have ourselves a verifiable way to run exactly
the (third party) action code we previously audited (you all audit your dependencies, right?)
### The slight wrinkle
At the time of writing (2020/02/04), GitHub does not natively support writing actions in Go:
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">Hi <a href="https://twitter.com/github?ref_src=twsrc%5Etfw">@github</a> - please can you provide a native way to write/use actions written in Go, that would allow me to do something like:<br><br> uses: $package@$version<br><br>which would then use <a href="https://t.co/fGOHqwoWSA">https://t.co/fGOHqwoWSA</a> for resolution, and <a href="https://t.co/hqG8e8gGf6">https://t.co/hqG8e8gGf6</a> for verification. Thanks <a href="https://twitter.com/hashtag/golang?src=hash&ref_src=twsrc%5Etfw">#golang</a></p>— Paul Jolly (@\_myitcv) <a href="https://twitter.com/_myitcv/status/1224288510053691393?ref_src=twsrc%5Etfw">February 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Instead, you have [the
choice](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-actions) of writing
either:
* Docker container-based actions (Linux only; Docker also works on Windows but the official GitHub Actions docs don't
yet list that as "supported")
* JavaScript-based actions (Linux, macOS, Windows)
With the goal of being fully cross-platform in mind, Docker actions are therefore ruled out.
I fell out of love with JavaScript a long time ago, a process that was accelerated by my working on
[GopherJS](https://github.com/gopherjs/gopherjs) (a compiler from Go to JavaScript). Having to return to its "unique"
approach didn't exactly fill me with glee, but given the current state of affairs there was, seemingly, no other option.
Indeed, the first couple of iterations of writing pure Go GitHub actions used GopherJS and the [Go's WebAssembly
port](https://github.com/golang/go/wiki/WebAssembly). However, both fell a long way short because neither support
fork/exec syscalls.
### The solution
With half a mind to GitHub eventually shipping native support for Go actions, I instead landed on a solution that uses a
light JavaScript wrapper around the `go` command. Let's explore that approach by writing an action.
But first, let's start by defining what our toy action will do. Incorporated into a workflow, this toy action will take
a single input, the user's name, and will output a line like:
```
{{PrintBlockOut "main out" -}}
```
(obviously adapted to the name of the user and the platform on which our workflow is running).
### Creating a module for our action
The documentation for [`cmd/go`](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) says of modules:
> A module is a collection of related Go packages. Modules are the unit of source code interchange and versioning.
The is precisely the definition we are after when it comes to GitHub Actions: we want users of the action to express
their dependency on semver versions of our action.
We start therefore by creating a module:
```
{{PrintBlock "define action repo root module" -}}
```
Before we define the action itself, we briefly discuss a key building block: the GitHub Actions API.
### GitHub Actions API
GitHub Actions has an [API for action
authors](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/development-tools-for-github-actions)
which is published as an [official GitHub Actions SDK for Node.js](https://github.com/actions/toolkit). [Seth
Vargo](https://twitter.com/sethvargo) has put together an [unofficial GitHub Actions SDK for
Go](https://github.com/sethvargo/go-githubactions) that "provides a Go-like interface for working with GitHub Actions."
Thank you, Seth!
Briefly skimming the [SDK documentation](https://pkg.go.dev/github.com/sethvargo/go-githubactions?tab=doc), it's clear
to see how we will be [getting our input](https://pkg.go.dev/github.com/sethvargo/go-githubactions?tab=doc#GetInput),
the name of the user:
```
// GetInput gets the input by the given name.
func GetInput(i string) string
```
We now have the relevant pieces in place to define our action.
### The Go code
The Go code is now, therefore, the simplest part of this action's definition.
```go
{{PrintBlock "action main" -}}
```
The platform-specific bit we will put behind build constrained files to demonstrate that aspects works too:
```go
{{PrintBlock "platform linux" -}}
```
Hopefully the contents for `platform_darwin.go` and `platform_windows.go` are obvious.
### Creating an action metadata file
The next step is to create an action metadata file:
```yaml
{{PrintBlock "action yml" -}}
```
Notice how we are running using NodeJS with an entry point of `index.js`; we talk about that next.
### The `index.js` entry point
Whilst we await native support for pure Go GitHub Actions, the simplest solution to running Go actions is a thin NodeJS
wrapper around `cmd/go`. For now this should be copy-pasted for each action you create:
```javascript
{{PrintBlock "action indexjs" -}}
```
Clearly copy-pasting this boilerplate, even in the short term, is not ideal. I am looking at ways to simplify and
automate this step using a Go tool (ideas also welcomed).
### Using our action
Now let's switch to creating a project that uses the Greeter action in one of its workflows:
```
{{PrintBlock "define usingaction repo root module" -}}
```
```yaml
{{PrintBlock "usingaction workflow" -}}
```
We specify a matrix of all platforms to demonstrate our action truly is cross-platform.
Given GitHub Actions don't natively support Go actions, and as we demonstrated in our `index.js` wrapper, we have to use
the `go` command. We therefore must have [`actions/setup-go`](https://github.com/actions/setup-go) as our first step in
any workflow that uses a Go action of this sort (until native actions come along).
Finally, both `uses: actions/setup-go` and `uses: myitcv/myfirstgoaction` specify specific commits, per advice earlier
in this post.
That's it! Let's commit, push and watch the build succeed!
![A successful build](/images/2020-02-04-build-success.png "A successful build")
### So what would native actions look like?
There are a few problems with the approach outlined above:
1. we need to explicitly install Go
2. we need to copy-paste our `index.js` wrapper for each Go action we create
3. we are not relying on the Go module proxy when using the action and hence have to specify a commit rather than a
semver version
Points 1 and 2 clearly disappear when native support is added.
Point 3 is particularly brittle because commits themselves can disappear from GitHub (force pushing to `master`, commit
no longer referenced by any tags or branches, gets cleaned up).
Therefore, given point 3 we ideally would use our action in a workflow in the following way:
```yaml
- name: Display a greeting
uses: github.com/myitcv/myfirstgoaction@v1.0.0
with:
name: Helena
```
such that when running the action, GitHub's infrastructure:
* creates a temporary module
* resolves the Go package `github.com/myitcv/myfirstgoaction` at version `v1.0.0` via
[proxy.golang.org](https://proxy.golang.org)
* runs the action via `go run github.com/myitcv/myfirstgoaction`
_Notice, the package path and module path being equal is just a coincidence of this example_
### Conclusion
Go provides some novel solutions to the problems of software dependencies. In this article I have demonstrated one way
in which pure Go actions can be written today (whilst we await native support from GitHub), leveraging the benefits and
protections of the Go Module Mirror, Index, and Checksum Database. Ultimately we all need to review our software
dependencies, but at least Go makes it easier to know that the world hasn't changed under our feet from build-to-build.
### Appendix
All of the source code used in this blog post is available on GitHub:
* [{{- PrintBlockOut "action repo" -}}]({{- PrintBlockOut "action repo url" -}})
* [{{- PrintBlockOut "usingaction repo" -}}]({{- PrintBlockOut "usingaction repo url" -}})
With thanks to [Daniel Martí](https://twitter.com/mvdan_) for reviewing this post.
-->
<h3 id="wait-theres-a-problem-with-github-actions">Wait, there’s a problem with GitHub Actions?</h3>
<p>Julien Renaux wrote a <a href="https://julienrenaux.fr/2019/12/20/github-actions-security-risk/">blog post</a> that does a good job
of laying out one of the core problems with GitHub Actions. The story goes roughly like this:</p>
<ul>
<li>someone writes and open-sources an action that requires secret credentials, e.g. DockerHub access token</li>
<li>lots of people start using the action via directives like <code class="language-plaintext highlighter-rouge">uses: good/action@v1</code> because it’s well written and useful</li>
<li>original author welcomes a new maintainer on board</li>
<li>somehow existing action version tags get moved, pointing to malicious code that steals secrets (any maintainer can
update a branch or a tag)</li>
</ul>
<p>Hence the specific advice is to use a commit hash to partially mitigate this risk:</p>
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">That’s why you need to specify the exact version (action@sha1) you want to use, so further changes won’t impact you.</p>— Alain Hélaïli (@AlainHelaili) <a href="https://twitter.com/AlainHelaili/status/1205238489056501761?ref_src=twsrc%5Etfw">December 12, 2019</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p><em>It is somewhat unfortunate at best that this isn’t the default advice in the official documentation; worth noting it
doesn’t defend against the commit disappearing.</em></p>
<p>The problems don’t stop there, because there is also the risk that transitive dependencies can do malicious things too:</p>
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">There is also a risk that the transitive dependencies can do malicious things.<a href="https://t.co/juffjxwxIr">https://t.co/juffjxwxIr</a></p>— DrSensor👹 (@dr\_sensor) <a href="https://twitter.com/dr_sensor/status/1208098900747284480?ref_src=twsrc%5Etfw">December 20, 2019</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>On top of this, it’s not made particularly clear to users that every action they use in their workflow is given implicit
access to an access token that has fairly <a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#permissions-for-the-github_token">wide-ranging read-write access to the host
repository</a>.</p>
<p>So we clearly have a software dependency problem here.</p>
<h3 id="why-go">Why Go?</h3>
<p><a href="https://twitter.com/_rsc">Russ Cox</a> has <a href="https://research.swtch.com/deps">repeatedly</a>
<a href="https://twitter.com/_rsc/status/1088109141409837063">written</a> about “Our Software Dependency Problem.” The basic
premise of those articles is that “software dependencies carry with them serious risks that are too often overlooked.”
Whilst Russ’ articles raise awareness of the risks and encourage more investigation of solutions (and I strongly
encourage you to read the article in full), the bottom line is that Go has a comprehensive solution to the major
problems outlined, via the <a href="https://proxy.golang.org/">Go Module Mirror</a>, <a href="https://index.golang.org/">Index</a>, and
<a href="https://sum.golang.org/">Checksum Database</a>, that ultimately results in the <code class="language-plaintext highlighter-rouge">go</code> command referencing an auditable
checksum database to authenticate modules. Coupled with the <a href="https://research.swtch.com/vgo-mvs">minimum version
selection</a> property of Go modules, we have ourselves a verifiable way to run exactly
the (third party) action code we previously audited (you all audit your dependencies, right?)</p>
<h3 id="the-slight-wrinkle">The slight wrinkle</h3>
<p>At the time of writing (2020/02/04), GitHub does not natively support writing actions in Go:</p>
<blockquote class="twitter-tweet tw-align-center"><p lang="en" dir="ltr">Hi <a href="https://twitter.com/github?ref_src=twsrc%5Etfw">@github</a> - please can you provide a native way to write/use actions written in Go, that would allow me to do something like:<br /><br /> uses: $package@$version<br /><br />which would then use <a href="https://t.co/fGOHqwoWSA">https://t.co/fGOHqwoWSA</a> for resolution, and <a href="https://t.co/hqG8e8gGf6">https://t.co/hqG8e8gGf6</a> for verification. Thanks <a href="https://twitter.com/hashtag/golang?src=hash&ref_src=twsrc%5Etfw">#golang</a></p>— Paul Jolly (@\_myitcv) <a href="https://twitter.com/_myitcv/status/1224288510053691393?ref_src=twsrc%5Etfw">February 3, 2020</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Instead, you have <a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-actions">the
choice</a> of writing
either:</p>
<ul>
<li>Docker container-based actions (Linux only; Docker also works on Windows but the official GitHub Actions docs don’t
yet list that as “supported”)</li>
<li>JavaScript-based actions (Linux, macOS, Windows)</li>
</ul>
<p>With the goal of being fully cross-platform in mind, Docker actions are therefore ruled out.</p>
<p>I fell out of love with JavaScript a long time ago, a process that was accelerated by my working on
<a href="https://github.com/gopherjs/gopherjs">GopherJS</a> (a compiler from Go to JavaScript). Having to return to its “unique”
approach didn’t exactly fill me with glee, but given the current state of affairs there was, seemingly, no other option.
Indeed, the first couple of iterations of writing pure Go GitHub actions used GopherJS and the <a href="https://github.com/golang/go/wiki/WebAssembly">Go’s WebAssembly
port</a>. However, both fell a long way short because neither support
fork/exec syscalls.</p>
<h3 id="the-solution">The solution</h3>
<p>With half a mind to GitHub eventually shipping native support for Go actions, I instead landed on a solution that uses a
light JavaScript wrapper around the <code class="language-plaintext highlighter-rouge">go</code> command. Let’s explore that approach by writing an action.</p>
<p>But first, let’s start by defining what our toy action will do. Incorporated into a workflow, this toy action will take
a single input, the user’s name, and will output a line like:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello, Helena! We are running on linux; Hooray!
</code></pre></div></div>
<p>(obviously adapted to the name of the user and the platform on which our workflow is running).</p>
<h3 id="creating-a-module-for-our-action">Creating a module for our action</h3>
<p>The documentation for <a href="https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more"><code class="language-plaintext highlighter-rouge">cmd/go</code></a> says of modules:</p>
<blockquote>
<p>A module is a collection of related Go packages. Modules are the unit of source code interchange and versioning.</p>
</blockquote>
<p>The is precisely the definition we are after when it comes to GitHub Actions: we want users of the action to express
their dependency on semver versions of our action.</p>
<p>We start therefore by creating a module:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ go mod init github.com/myitcvblog/myfirstgoaction
go: creating new go.mod: module github.com/myitcvblog/myfirstgoaction
</code></pre></div></div>
<p>Before we define the action itself, we briefly discuss a key building block: the GitHub Actions API.</p>
<h3 id="github-actions-api">GitHub Actions API</h3>
<p>GitHub Actions has an <a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions/development-tools-for-github-actions">API for action
authors</a>
which is published as an <a href="https://github.com/actions/toolkit">official GitHub Actions SDK for Node.js</a>. <a href="https://twitter.com/sethvargo">Seth
Vargo</a> has put together an <a href="https://github.com/sethvargo/go-githubactions">unofficial GitHub Actions SDK for
Go</a> that “provides a Go-like interface for working with GitHub Actions.”
Thank you, Seth!</p>
<p>Briefly skimming the <a href="https://pkg.go.dev/github.com/sethvargo/go-githubactions?tab=doc">SDK documentation</a>, it’s clear
to see how we will be <a href="https://pkg.go.dev/github.com/sethvargo/go-githubactions?tab=doc#GetInput">getting our input</a>,
the name of the user:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// GetInput gets the input by the given name.
func GetInput(i string) string
</code></pre></div></div>
<p>We now have the relevant pieces in place to define our action.</p>
<h3 id="the-go-code">The Go code</h3>
<p>The Go code is now, therefore, the simplest part of this action’s definition.</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">cat</span> <span class="n">main</span><span class="o">.</span><span class="k">go</span>
<span class="k">package</span> <span class="n">main</span>
<span class="k">import</span> <span class="p">(</span>
<span class="s">"fmt"</span>
<span class="s">"github.com/sethvargo/go-githubactions"</span>
<span class="p">)</span>
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">name</span> <span class="o">:=</span> <span class="n">githubactions</span><span class="o">.</span><span class="n">GetInput</span><span class="p">(</span><span class="s">"name"</span><span class="p">)</span>
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Hello, %v! We are running on %v; Hooray!</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">platform</span><span class="p">())</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The platform-specific bit we will put behind build constrained files to demonstrate that aspects works too:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">cat</span> <span class="n">platform_linux</span><span class="o">.</span><span class="k">go</span>
<span class="k">package</span> <span class="n">main</span>
<span class="k">func</span> <span class="n">platform</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
<span class="k">return</span> <span class="s">"linux"</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Hopefully the contents for <code class="language-plaintext highlighter-rouge">platform_darwin.go</code> and <code class="language-plaintext highlighter-rouge">platform_windows.go</code> are obvious.</p>
<h3 id="creating-an-action-metadata-file">Creating an action metadata file</h3>
<p>The next step is to create an action metadata file:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">$ cat action.yml</span>
<span class="na">name</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Greeter'</span>
<span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Print</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">platform-aware</span><span class="nv"> </span><span class="s">greeting</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">user'</span>
<span class="na">inputs</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span>
<span class="na">description</span><span class="pi">:</span> <span class="s1">'</span><span class="s">The</span><span class="nv"> </span><span class="s">name</span><span class="nv"> </span><span class="s">of</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">user'</span>
<span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">runs</span><span class="pi">:</span>
<span class="na">using</span><span class="pi">:</span> <span class="s1">'</span><span class="s">node12'</span>
<span class="na">main</span><span class="pi">:</span> <span class="s1">'</span><span class="s">index.js'</span>
</code></pre></div></div>
<p>Notice how we are running using NodeJS with an entry point of <code class="language-plaintext highlighter-rouge">index.js</code>; we talk about that next.</p>
<h3 id="the-indexjs-entry-point">The <code class="language-plaintext highlighter-rouge">index.js</code> entry point</h3>
<p>Whilst we await native support for pure Go GitHub Actions, the simplest solution to running Go actions is a thin NodeJS
wrapper around <code class="language-plaintext highlighter-rouge">cmd/go</code>. For now this should be copy-pasted for each action you create:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span> <span class="nx">cat</span> <span class="nx">index</span><span class="p">.</span><span class="nx">js</span>
<span class="dl">"</span><span class="s2">use strict</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">spawn</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">child_process</span><span class="dl">"</span><span class="p">).</span><span class="nx">spawn</span><span class="p">;</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nx">run</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">args</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="nx">spawn</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nx">args</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="p">{</span>
<span class="na">stdio</span><span class="p">:</span> <span class="dl">"</span><span class="s2">inherit</span><span class="dl">"</span><span class="p">,</span>
<span class="na">cwd</span><span class="p">:</span> <span class="nx">__dirname</span>
<span class="p">});</span>
<span class="kd">const</span> <span class="nx">exitCode</span> <span class="o">=</span> <span class="k">await</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">cmd</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">close</span><span class="dl">"</span><span class="p">,</span> <span class="nx">resolve</span><span class="p">);</span>
<span class="p">});</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">exitCode</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="nx">exitCode</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">(</span><span class="k">async</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">path</span><span class="dl">"</span><span class="p">);</span>
<span class="k">await</span> <span class="nx">run</span><span class="p">(</span><span class="dl">"</span><span class="s2">go</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">run</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">.</span><span class="dl">"</span><span class="p">);</span>
<span class="p">})();</span>
</code></pre></div></div>
<p>Clearly copy-pasting this boilerplate, even in the short term, is not ideal. I am looking at ways to simplify and
automate this step using a Go tool (ideas also welcomed).</p>
<h3 id="using-our-action">Using our action</h3>
<p>Now let’s switch to creating a project that uses the Greeter action in one of its workflows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ go mod init github.com/myitcvblog/usingmyfirstgoaction
go: creating new go.mod: module github.com/myitcvblog/usingmyfirstgoaction
</code></pre></div></div>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">$ cat .github/workflows/test.yml</span>
<span class="na">on</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">push</span><span class="pi">,</span> <span class="nv">pull_request</span><span class="pi">]</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Test</span>
<span class="na">jobs</span><span class="pi">:</span>
<span class="na">test</span><span class="pi">:</span>
<span class="na">strategy</span><span class="pi">:</span>
<span class="na">matrix</span><span class="pi">:</span>
<span class="na">platform</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">ubuntu-latest</span><span class="pi">,</span> <span class="nv">macos-latest</span><span class="pi">,</span> <span class="nv">windows-latest</span><span class="pi">]</span>
<span class="na">runs-on</span><span class="pi">:</span> <span class="s">${{ matrix.platform }}</span>
<span class="na">steps</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/setup-go@9fbc767707c286e568c92927bbf57d76b73e0892</span>
<span class="na">with</span><span class="pi">:</span>
<span class="na">go-version</span><span class="pi">:</span> <span class="s1">'</span><span class="s">1.14.x'</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Display a greeting</span>
<span class="na">uses</span><span class="pi">:</span> <span class="s">myitcvblog/myfirstgoaction@7096ad461380fef1c02fb53935bd26153465906b</span>
<span class="na">with</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Helena</span>
</code></pre></div></div>
<p>We specify a matrix of all platforms to demonstrate our action truly is cross-platform.</p>
<p>Given GitHub Actions don’t natively support Go actions, and as we demonstrated in our <code class="language-plaintext highlighter-rouge">index.js</code> wrapper, we have to use
the <code class="language-plaintext highlighter-rouge">go</code> command. We therefore must have <a href="https://github.com/actions/setup-go"><code class="language-plaintext highlighter-rouge">actions/setup-go</code></a> as our first step in
any workflow that uses a Go action of this sort (until native actions come along).</p>
<p>Finally, both <code class="language-plaintext highlighter-rouge">uses: actions/setup-go</code> and <code class="language-plaintext highlighter-rouge">uses: myitcv/myfirstgoaction</code> specify specific commits, per advice earlier
in this post.</p>
<p>That’s it! Let’s commit, push and watch the build succeed!</p>
<p><img src="/images/2020-02-04-build-success.png" alt="A successful build" title="A successful build" /></p>
<h3 id="so-what-would-native-actions-look-like">So what would native actions look like?</h3>
<p>There are a few problems with the approach outlined above:</p>
<ol>
<li>we need to explicitly install Go</li>
<li>we need to copy-paste our <code class="language-plaintext highlighter-rouge">index.js</code> wrapper for each Go action we create</li>
<li>we are not relying on the Go module proxy when using the action and hence have to specify a commit rather than a
semver version</li>
</ol>
<p>Points 1 and 2 clearly disappear when native support is added.</p>
<p>Point 3 is particularly brittle because commits themselves can disappear from GitHub (force pushing to <code class="language-plaintext highlighter-rouge">master</code>, commit
no longer referenced by any tags or branches, gets cleaned up).</p>
<p>Therefore, given point 3 we ideally would use our action in a workflow in the following way:</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Display a greeting</span>
<span class="na">uses</span><span class="pi">:</span> <span class="s">github.com/myitcv/myfirstgoaction@v1.0.0</span>
<span class="na">with</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Helena</span>
</code></pre></div></div>
<p>such that when running the action, GitHub’s infrastructure:</p>
<ul>
<li>creates a temporary module</li>
<li>resolves the Go package <code class="language-plaintext highlighter-rouge">github.com/myitcv/myfirstgoaction</code> at version <code class="language-plaintext highlighter-rouge">v1.0.0</code> via
<a href="https://proxy.golang.org">proxy.golang.org</a></li>
<li>runs the action via <code class="language-plaintext highlighter-rouge">go run github.com/myitcv/myfirstgoaction</code></li>
</ul>
<p><em>Notice, the package path and module path being equal is just a coincidence of this example</em></p>
<h3 id="conclusion">Conclusion</h3>
<p>Go provides some novel solutions to the problems of software dependencies. In this article I have demonstrated one way
in which pure Go actions can be written today (whilst we await native support from GitHub), leveraging the benefits and
protections of the Go Module Mirror, Index, and Checksum Database. Ultimately we all need to review our software
dependencies, but at least Go makes it easier to know that the world hasn’t changed under our feet from build-to-build.</p>
<h3 id="appendix">Appendix</h3>
<p>All of the source code used in this blog post is available on GitHub:</p>
<ul>
<li><a href="https://github.com/myitcvblog/myfirstgoaction">github.com/myitcvblog/myfirstgoaction
</a></li>
<li><a href="https://github.com/myitcvblog/usingmyfirstgoaction">github.com/myitcvblog/usingmyfirstgoaction
</a></li>
</ul>
<p>With thanks to <a href="https://twitter.com/mvdan_">Daniel Martí</a> for reviewing this post.
<!-- END --></p>
<p><br />
<em>Edit 2020-02-13: move to using <code class="language-plaintext highlighter-rouge">github.com/myitcvblog</code> as the home for these examples</em><br />
<em>Edit 2020-02-13: I’ve now <a href="https://github.com/actions/runner/issues/333">raised an issue</a> to request native support for pure Go actions</em><br />
<em>Edit 2020-03-04: Updated link to Julien Renaux’s blog post now that original tweet is no longer availabe</em><br /></p>paulI recently converted the govim project to use GitHub Actions. The move away from TravisCI was largely motivated by more generous concurrency limits (GitHub’s 20 jobs vs TravisCI’s 5), faster job startup times, and solid cross-platform support. But there was also the promise of making it easy to extend workflows with composable third-party actions. This post demonstrates how to write cross-platform, pure Go GitHub actions that you can use in your workflows and share with others. But first we start by motivating the real problem we are trying to solve.govim - a Go development plugin for Vim82019-04-17T00:00:00+01:002019-04-17T00:00:00+01:00https://blog.myitcv.io/2019/04/17/govim<p>Command <code class="language-plaintext highlighter-rouge">github.com/myitcv/govim/cmd/govim</code> (referred to simply as <code class="language-plaintext highlighter-rouge">govim</code>) is a Go development plugin for Vim8, much
like <a href="https://github.com/fatih/vim-go"><code class="language-plaintext highlighter-rouge">vim-go</code></a>. But unlike <code class="language-plaintext highlighter-rouge">vim-go</code>, <code class="language-plaintext highlighter-rouge">govim</code> is written in Go, not VimScript. It has
features like code completion, format-on-save, hover details and go-to definition, all of which are driven by
<a href="https://godoc.org/golang.org/x/tools/cmd/gopls"><code class="language-plaintext highlighter-rouge">gopls</code></a>, the Language Server Protocol (LSP) server for Go. See <a href="https://github.com/myitcv/govim/wiki/govim-plugin-API">the
wiki</a> for more feature details. Installation instructions can be
found in the <a href="https://github.com/myitcv/govim/blob/master/README.md">main <code class="language-plaintext highlighter-rouge">README</code></a>.</p>
<p>Package <a href="https://godoc.org/github.com/myitcv/govim"><code class="language-plaintext highlighter-rouge">github.com/myitcv/govim</code></a> provides an API for plugin developers to
interface with Vim8 in Go, i.e. write Vim8 plugins in Go rather than VimScript. More details
<a href="https://github.com/myitcv/govim/blob/master/PLUGIN_AUTHORS.md">here</a>.</p>
<p>The <a href="https://github.com/myitcv/govim/wiki/FAQ">FAQ</a> covers a number of important questions, including:</p>
<ul>
<li>Why have you created govim? What is/was wrong with vim-go?</li>
<li>What versions of Vim and Go are supported with govim?</li>
<li>Why should I use govim over vim-go/vim-lsp/…?</li>
<li>…</li>
</ul>
<p>I’ve given two talks on <code class="language-plaintext highlighter-rouge">govim</code>, the first at <a href="https://gophers.london">London Gophers</a>:</p>
<p>
<a href="https://www.youtube.com/watch?v=bNFl7HcyDao"><img src="/images/youtube.png" style="width: 30px" /></a> <a href="https://www.youtube.com/watch?v=bNFl7HcyDao">London Gophers YouTube recording</a>
</p>
<p>
<a href="https://talks.godoc.org/github.com/myitcv/talks/2019-04-17-govim/main.slide#1"><img src="/images/gopher.png" style="width: 30px" /></a> <a href="https://talks.godoc.org/github.com/myitcv/talks/2019-04-17-govim/main.slide#1">London Gophers Slides</a>
</p>
<p>The second at <a href="https://www.meetup.com/Vim-London/">Vim London</a>, in which I go into more details on the Vim side, as well
as covering how the plugin is tested:</p>
<p>
<a href="https://www.youtube.com/watch?v=qj81tDDqzrQ"><img src="/images/youtube.png" style="width: 30px" /></a> <a href="https://www.youtube.com/watch?v=qj81tDDqzrQ">Vim London YouTube recording</a>
</p>
<p>
<a href="https://talks.godoc.org/github.com/myitcv/talks/2019-04-25-govim-vim-london/main.slide#1"><img src="/images/gopher.png" style="width: 30px" /></a> <a href="https://talks.godoc.org/github.com/myitcv/talks/2019-04-25-govim-vim-london/main.slide#1">Vim London Slides</a>
</p>
<p>As ever, contributions are very much welcome in the form of feedback, issues and PRs.</p>paulCommand github.com/myitcv/govim/cmd/govim (referred to simply as govim) is a Go development plugin for Vim8, much like vim-go. But unlike vim-go, govim is written in Go, not VimScript. It has features like code completion, format-on-save, hover details and go-to definition, all of which are driven by gopls, the Language Server Protocol (LSP) server for Go. See the wiki for more feature details. Installation instructions can be found in the main README.gg - cache-based wrapper around go generate2019-03-29T00:00:00+00:002019-03-29T00:00:00+00:00https://blog.myitcv.io/2019/03/29/gg---cached-based-wrapper-around-go-generate<p><a href="https://godoc.org/myitcv.io/cmd/gg"><code class="language-plaintext highlighter-rouge">gg</code></a> is a cache-based wrapper around <code class="language-plaintext highlighter-rouge">go generate</code>.</p>
<p>Like <code class="language-plaintext highlighter-rouge">go generate</code>, <code class="language-plaintext highlighter-rouge">gg</code> understands <code class="language-plaintext highlighter-rouge">//go:generate</code> directives. But unlike <code class="language-plaintext highlighter-rouge">go generate</code>, <code class="language-plaintext highlighter-rouge">gg</code>:</p>
<ul>
<li>understands the dependency graph between packages to be generated, including the generators themselves</li>
<li>repeatedly runs <code class="language-plaintext highlighter-rouge">//go:generate</code> directives in a package until a fixed point is reached, allowing generators to chain
together</li>
<li>caches generated artefacts, making subsequent runs with the same inputs extremely fast (because the <code class="language-plaintext highlighter-rouge">//go:generate</code>
directives do not need to be re-run)</li>
<li>understands generator flags prefixed with <code class="language-plaintext highlighter-rouge">-infiles:</code> to declare glob patterns of files the directive will consume</li>
<li>understands generator flags prefixed with <code class="language-plaintext highlighter-rouge">-outdir:</code> to mean that the directive will generate files to the named
directory in addition to the current package’s directory</li>
<li>has a special <code class="language-plaintext highlighter-rouge">//go:generate:gg</code> directive which allows code generation to <code class="language-plaintext highlighter-rouge">break</code> under certain conditions</li>
</ul>
<p>More details <a href="https://godoc.org/myitcv.io/cmd/gg">in the docs</a>.</p>
<p>I also gave a talk at <a href="https://www.meetup.com/GoSheffield/">GoSheffield</a>:</p>
<p>
<a href="https://talks.godoc.org/github.com/myitcv/talks/2019-02-07-code-generation/main.slide#1"><img src="/images/gopher.png" style="width: 30px" /></a> <a href="https://talks.godoc.org/github.com/myitcv/talks/2019-02-07-code-generation/main.slide#1">GoSheffield Slides</a>
</p>
<p>As ever, contributions are very much welcome in the form of feedback, issues and PRs <a href="https://github.com/myitcv/x">over in the GitHub
repo</a>.</p>paulgg is a cache-based wrapper around go generate.London Gophers - 2018 in review2018-12-01T00:00:00+00:002018-12-01T00:00:00+00:00https://blog.myitcv.io/2018/12/01/london-gophers---2018-in-review<p>As one of the co-organisers of <a href="https://gophers.london">London Gophers</a>, along with <a href="https://twitter.com/domgreen">Dominic
Green</a>, <a href="https://twitter.com/londongopher_">Antonio Troina</a> and <a href="https://twitter.com/kasiazien">Kat
Zień</a>, I thought I would jot down a few highlights from 2018:</p>
<ul>
<li>we’ve seen the community grow from 1,727 to a fantastic 2,652 members</li>
<li>by the end of the year will will have held 12 monthly Meetups at various awesome locations in London</li>
<li>enjoyed first-time talks from no fewer than ten Gophers</li>
<li>welcomed back regular speakers <a href="https://twitter.com/mvdan_?lang=en">Daniel Martí</a>, <a href="https://twitter.com/lizrice">Liz
Rice</a> and <a href="https://twitter.com/JohanBrandhorst">Johan Brandhorst</a></li>
<li>helped to run two Go Contributor workshops (organised by <a href="https://twitter.com/mvdan_?lang=en">Daniel Martí</a>)</li>
<li>welcomed <a href="https://twitter.com/kasiazien">Kat Zień</a> to the organising team</li>
<li>seen the growth of our <a href="https://www.youtube.com/c/LondonGophers">YouTube channel</a> and viewer figures thanks to the
technical wizardry of <a href="https://twitter.com/londongopher_">Antonio Troina</a></li>
<li>enjoyed some hilarious tweets/gifs on our <a href="https://twitter.com/LondonGophers">Twitter feed</a></li>
<li>… the list goes on</li>
</ul>
<p>We’ve also started publishing details of how we run London Gophers in our <a href="https://github.com/go-london-user-group">GitHub
repo</a>. The main aim being to share our learnings with other Meetup organisers
(principally in the UK, on the basis legal/financial structures will be most similar), but also to be fully transparent
with our members and sponsors on how things are run.</p>
<p>In summary: 2018 was an exciting year, plenty to look forward to in 2019!</p>
<p>A huge thanks to everyone who attended any of our events, to our speakers, to our sponsors, and of course to my fellow
organisers.</p>
<p>As ever, we greatly appreciate, welcome and encourage feedback. Please contact the organisers via
<a href="mailto:glug-organisers@googlegroups.com">glug-organisers@googlegroups.com</a>.</p>paulAs one of the co-organisers of London Gophers, along with Dominic Green, Antonio Troina and Kat Zień, I thought I would jot down a few highlights from 2018:github.com/myitcv/gobin2018-10-24T00:00:00+01:002018-10-24T00:00:00+01:00https://blog.myitcv.io/2018/10/24/github.com-myitcv-gobin<p><a href="https://github.com/myitcv/gobin"><code class="language-plaintext highlighter-rouge">github.com/myitcv/gobin</code></a> is an experimental, module-aware command to install/run main packages.</p>
<p>Compared to the Go 1.11 series <code class="language-plaintext highlighter-rouge">cmd/go</code>, with <code class="language-plaintext highlighter-rouge">gobin</code> you:</p>
<ul>
<li>get some of the behaviour of <code class="language-plaintext highlighter-rouge">go get</code>, <code class="language-plaintext highlighter-rouge">go install</code> and <code class="language-plaintext highlighter-rouge">go run</code> combined</li>
<li>can have multiple versions of a tool available without needing to worry about setting <code class="language-plaintext highlighter-rouge">PATH</code></li>
<li>have the equivalent of <code class="language-plaintext highlighter-rouge">go get</code> whilst in module-aware mode but this does not modify your <code class="language-plaintext highlighter-rouge">go.mod</code>; indeed you can
choose whether you want to run in global mode (the default) or main-module mode for the install/run operation</li>
<li>can run a main package without the overhead of the linking phase, e.g. within code generation</li>
</ul>
<p>More detailed on the rationale etc are covered in <a href="https://github.com/myitcv/gobin/blob/master/README.md">the main
<code class="language-plaintext highlighter-rouge">README</code></a> and <a href="https://github.com/myitcv/gobin/wiki/FAQ">the
FAQ</a>.</p>
<p><code class="language-plaintext highlighter-rouge">gobin</code> is an experiment, as such there are no expectations over its future.</p>
<p>There are a number of potential outcomes, not limited to the following list:</p>
<ul>
<li>it dies; the hypothesis being tested by <code class="language-plaintext highlighter-rouge">gobin</code> proves incorrect, unworkable etc</li>
<li>it lives on as a separate tool outside of the Go distribution</li>
<li>parts of <code class="language-plaintext highlighter-rouge">gobin</code> are absorbed into the <code class="language-plaintext highlighter-rouge">cmd/go</code> tool</li>
<li>a variant of gobin is vendored and distributed alongside the <code class="language-plaintext highlighter-rouge">cmd/go</code> tool, much like <code class="language-plaintext highlighter-rouge">godoc</code> was in in Go 1.11 and earlier</li>
<li>…</li>
</ul>
<p>As ever, contributions in the form of feedback, issues and PRs, greatly appreciated.</p>paulgithub.com/myitcv/gobin is an experimental, module-aware command to install/run main packages.github.com/rogpeppe/go-internal2018-10-23T00:00:00+01:002018-10-23T00:00:00+01:00https://blog.myitcv.io/2018/10/23/github.com-rogpeppe-go-internal<p>Packages <a href="https://godoc.org/github.com/rogpeppe/go-internal"><code class="language-plaintext highlighter-rouge">github.com/rogpeppe/go-internal/...</code></a> represent an
opinionated selection of internal packages and functionality factored out from the Go standard library and <code class="language-plaintext highlighter-rouge">cmd/go</code>.
This work was started by <a href="https://twitter.com/rogpeppe?lang=en">Roger Peppe</a>, with contributions from <a href="https://twitter.com/mvdan_?lang=en">Daniel
Martí</a> and myself.</p>
<p>It includes:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">cache</code>: Package cache implements a build artifact cache.</li>
<li><code class="language-plaintext highlighter-rouge">cmd/testscript</code>: Package testscript provides support for defining filesystem-based tests by creating scripts in a
directory.</li>
<li><code class="language-plaintext highlighter-rouge">lockedfile</code>: Package lockedfile creates and manipulates files whose contents should only change atomically.</li>
<li><code class="language-plaintext highlighter-rouge">modfile</code>: Package modfile implements parsing and formatting for go.mod files.</li>
<li><code class="language-plaintext highlighter-rouge">module</code>: Package module defines the module.Version type along with support code.</li>
<li><code class="language-plaintext highlighter-rouge">par</code>: Package par implements parallel execution helpers.</li>
<li><code class="language-plaintext highlighter-rouge">renameio</code>: Package renameio writes files atomically by renaming temporary files.</li>
<li><code class="language-plaintext highlighter-rouge">semver</code>: Package semver implements comparison of semantic version strings.</li>
<li><code class="language-plaintext highlighter-rouge">testscript</code>: Package testscript provides support for defining filesystem-based tests by creating scripts in a
directory.</li>
<li><code class="language-plaintext highlighter-rouge">txtar</code>: Package txtar implements a trivial text-based file archive format.</li>
</ul>
<p>See the <a href="https://godoc.org/github.com/rogpeppe/go-internal">docs for <code class="language-plaintext highlighter-rouge">github.com/rogpeppe/go-internal</code></a> for a more
current and complete list.</p>
<p>Issues <a href="https://github.com/golang/go/issues/28101">#28101</a> and <a href="https://github.com/golang/go/issues/31761">#31761</a> track
the more official exporting of these packages.</p>paulPackages github.com/rogpeppe/go-internal/... represent an opinionated selection of internal packages and functionality factored out from the Go standard library and cmd/go. This work was started by Roger Peppe, with contributions from Daniel Martí and myself.golang-tools2018-09-18T00:00:00+01:002018-09-18T00:00:00+01:00https://blog.myitcv.io/2018/09/18/golang-tools<blockquote>
<p><code class="language-plaintext highlighter-rouge">golang-tools</code> is a development list for the Go Programming Language. The list is for discussion of the development of
tools that analyze and manipulate Go source code, including editor/IDE plugins.</p>
</blockquote>
<p>At <a href="https://www.gophercon.com">GopherCon 2018</a>, I attended the Go Contributor Summit with the hope of participating in a
session where we could discuss <a href="https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more">Go Modules</a>, tooling,
editor/IDE support and the like. Then Marcel, Ian and Robert rained on my parade with the <a href="https://go.googlesource.com/proposal/+/master/design/go2draft.md">Go 2 Design
Drafts</a>!</p>
<p>But I got chatting to Ian Cottrell about <a href="https://godoc.org/golang.org/x/tools/go/packages"><code class="language-plaintext highlighter-rouge">go/packages</code></a>, tooling,
editor/IDE support for Go amongst other things, and thought it would be useful to gather interested parties at GopherCon
to talk about all of these topics in the context of Go modules, but also generally where things are heading.</p>
<p>We did a best-efforts job of gathering a list of folks at GopherCon we thought would be interested in such a session. I
also augmented that list with folks I knew would also be interested but were unfortunately not at GopherCon.</p>
<p>And so at GopherCon 2018 we held the first <a href="https://github.com/golang/go/wiki/golang-tools"><code class="language-plaintext highlighter-rouge">golang-tools</code></a> session.
What started as a kick-off meeting is now:</p>
<ul>
<li>a <a href="https://groups.google.com/forum/#!forum/golang-tools">mailing list</a></li>
<li>an active <a href="https://gophers.slack.com/">Gophers Slack</a> <code class="language-plaintext highlighter-rouge">#tools</code> channel (<a href="https://invite.slack.golangbridge.org">sign
up</a>)</li>
<li>monthly Google Hangout <a href="https://github.com/golang/go/wiki/golang-tools#catch-up-calls">catch-up calls</a></li>
</ul>
<p>Each of the catch up sessions is recorded and published on YouTube, along with notes summarising discussion (<a href="https://github.com/golang/go/wiki/golang-tools#catch-up-calls">link to
published notes/recordings</a>).</p>
<p>The group is open to everyone, especially those with an interest in build tools to work with the Go programming
language.</p>paulgolang-tools is a development list for the Go Programming Language. The list is for discussion of the development of tools that analyze and manipulate Go source code, including editor/IDE plugins.Go Modules support for GopherJS2018-08-10T00:00:00+01:002018-08-10T00:00:00+01:00https://blog.myitcv.io/2018/08/10/go-modules-support-for-gopherjs<p>Introducing <a href="https://github.com/myitcv/gopherjs">https://github.com/myitcv/gopherjs</a>, a fork of
<a href="https://github.com/gopherjs/gopherjs">https://github.com/gopherjs/gopherjs</a> that includes almost complete <a href="https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more">Go
Modules</a> support, as well as some other bug fixes and
goodies. The medium to long term plan is to have these changes be merged back into the main repo, but for now they will
be maintained in this fork.</p>
<p>When in module mode, this fork should be used via a <code class="language-plaintext highlighter-rouge">replace</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module mod.com
replace github.com/gopherjs/gopherjs => github.com/myitcv/gopherjs latest
</code></pre></div></div>
<p>The current list of changes found in the https://github.com/myitcv/gopherjs fork includes:</p>
<ul>
<li>Almost complete Go Modules support</li>
<li>Significantly improved test coverage of <code class="language-plaintext highlighter-rouge">gopherjs</code> via
<a href="https://godoc.org/github.com/rogpeppe/go-internal/testscript"><code class="language-plaintext highlighter-rouge">testscript</code></a> test scripts</li>
<li>Quicker and more accurate <code class="language-plaintext highlighter-rouge">gopherjs</code> builds/installs thanks to a <a href="https://godoc.org/github.com/rogpeppe/go-internal/cache">build artefact
cache</a> (similar to that used by <code class="language-plaintext highlighter-rouge">cmd/go</code>)</li>
<li>Experimental addition of <a href="https://godoc.org/github.com/myitcv/gopherjs/js#MakeFullWrapper"><code class="language-plaintext highlighter-rouge">MakeFullWrapper</code></a> to
<code class="language-plaintext highlighter-rouge">github.com/gopherjs/gopherjs/js</code> (note this should still be imported as <code class="language-plaintext highlighter-rouge">github.com/gopherjs/gopherjs/js</code>)</li>
<li>Improved contributor experience:
<ul>
<li>JavaScript shims maintained in <code class="language-plaintext highlighter-rouge">.js</code> files</li>
<li>Node-based tooling to help format/manage the <code class="language-plaintext highlighter-rouge">.js</code> files</li>
</ul>
</li>
<li>Various bug fixes</li>
</ul>
<p>See the <a href="https://github.com/myitcv/gopherjs/commits/master">commit log</a> for full details.</p>paulIntroducing https://github.com/myitcv/gopherjs, a fork of https://github.com/gopherjs/gopherjs that includes almost complete Go Modules support, as well as some other bug fixes and goodies. The medium to long term plan is to have these changes be merged back into the main repo, but for now they will be maintained in this fork.Go Modules By Example2018-07-30T00:00:00+01:002018-07-30T00:00:00+01:00https://blog.myitcv.io/2018/07/30/go-modules-by-example<p><a href="https://github.com/go-modules-by-example/index/blob/master/README.md"><em>Go modules by example</em></a> is a series of
work-along guides that look to help explain how <a href="https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more">Go
modules</a> work and how to get things done. They are
designed to complement the official Go documentation and the <a href="https://github.com/golang/go/wiki/Modules">Go modules
wiki</a>.</p>
<p>The guides are being released in no particular order and will instead be curated into a more cogent order/structure (in
conjunction with the modules wiki) at a later date.</p>
<p>See the <a href="https://github.com/go-modules-by-example/index/blob/master/README.md">main <code class="language-plaintext highlighter-rouge">README</code></a> for a list of full list of
guides including:</p>
<ul>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/009_submodules/README.md">How to use submodules</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/008_vendor_example/README.md">Using modules to manage vendor</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/012_modvendor/README.md">Creating a module download cache “vendor”</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/011_using_gohack/README.md">Using <code class="language-plaintext highlighter-rouge">gohack</code> to “hack” on dependencies</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/003_migrate_buffalo/README.md">Migrating Buffalo from <code class="language-plaintext highlighter-rouge">dep</code> to go modules</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/010_tools/README.md">Tools as dependencies</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/013_cyclic/README.md">Cyclic module dependencies</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/014_mod_graph/README.md">Visually analysing module dependencies</a></li>
<li><a href="https://github.com/go-modules-by-example/index/blob/master/015_semantic_import_versioning/README.md">Semantic import versioning by example</a></li>
</ul>
<p>.. and more.</p>
<p>Any help greatly appreciated! Be it in the form of feedback, issues or PRs.</p>paulGo modules by example is a series of work-along guides that look to help explain how Go modules work and how to get things done. They are designed to complement the official Go documentation and the Go modules wiki.myitcv.io/react upgraded to React 162017-12-08T00:00:00+00:002017-12-08T00:00:00+00:00https://blog.myitcv.io/2017/12/08/myitcv.io_react-upgraded-to-react-16<p>Following the <a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html">release of React <code class="language-plaintext highlighter-rouge">16.2.0</code></a>,
<a href="https://myitcv.io/react"><code class="language-plaintext highlighter-rouge">myitcv.io/react</code></a> has been upgraded to bundle React 16 by default. Per <a href="https://github.com/myitcv/x/blob/master/react/_doc/README.md">the
README</a>, React 15 support is being maintained on <a href="https://github.com/myitcv/react/tree/react_15">a
branch</a>.</p>
<p>Support is also included for <a href="https://reactjs.org/docs/fragments.html">Fragments</a>:</p>
<blockquote>
<p>“A common pattern in React is for a
component to return multiple elements. Fragments let you group a list of children without adding extra nodes to the
DOM.”</p>
</blockquote>
<p>Here is an example of a <code class="language-plaintext highlighter-rouge">react.Fragment</code> being used:</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="p">(</span><span class="n">a</span> <span class="n">AppDef</span><span class="p">)</span> <span class="n">Render</span><span class="p">()</span> <span class="n">react</span><span class="o">.</span><span class="n">Element</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">react</span><span class="o">.</span><span class="n">Fragment</span><span class="p">(</span>
<span class="n">react</span><span class="o">.</span><span class="n">H1</span><span class="p">(</span><span class="no">nil</span><span class="p">,</span>
<span class="n">react</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">),</span>
<span class="p">),</span>
<span class="n">react</span><span class="o">.</span><span class="n">P</span><span class="p">(</span><span class="no">nil</span><span class="p">,</span>
<span class="n">react</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="s">"This is my first GopherJS React App."</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Please <a href="https://github.com/myitcv/x/issues/new?title=react:">raise any issues on Github</a>.</p>paulFollowing the release of React 16.2.0, myitcv.io/react has been upgraded to bundle React 16 by default. Per the README, React 15 support is being maintained on a branch.