Skip to content

Building and publishing deb/rpm packages with goreleaser and gemfury#

I am a huge fan of a goreleaser tool that enables users to build Go projects and package/publish build artifacts in a fully automated and highly customizable way. We've have been using goreleaser with all our recent projects and we couldn't be any happier since then.

But once the artifacts are built and published, the next important step is to make them easily installable. Especially if you provide deb/rpm packages which are built with NFPM integration.

The "challenge" with deb/rpm packages comes to light when project owners want to add those packages to Apt/Yum repositories. Goreleaser doesn't provide any integrations with 3rd party repositories nor there are Apt/Yum repositories which are free and provide an API to upload artifacts. Or are there?

Gemfury aka

Actually there is at least one - the project that does just that (and even more).


Gemfury is a private package repository to help you easily reuse code without worrying about its hosting or deployment. It integrates directly with existing package management tools that you already use.

Among other repositories, Fury provides a Yum/Apt repo for pre-built deb/rpm packages. It is free for public packages, which makes it a good choice for OSS projects. It also sports a hefty number of options to upload artifacts, from a simple curl to a push via its own CLI tool.


Just register within the service and generate a push token, and you are good to go leveraging Goreleaser to push your artifacts to Fury.

Using Goreleaser with Fury#

Step 1: Adding Fury' token#

Once you have a Fury' push token, it is a matter of a few lines of code on the Goreleaser side.

I am using Goreleaser' Github action to build and publish artifacts, therefore I added push token to repo's secrets and added it as another environment variable of a goreleaser action:

# github action workflow file
name: Release
      - v*
    runs-on: ubuntu-latest
      - name: Checkout
        uses: actions/checkout@v2
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v2
          go-version: 1.15
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v2
          version: v0.155.0
          args: release --rm-dist
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }}

This will make our FURYPUSHTOKEN secret value to be available inside the Goreleaser' Env vars under the FURY_TOKEN name.

Step 2: Add ID for NFPM builds#

In the nfpm section of your .goreleaser.yml file add id field. This identification string will be used in Step 3 to scope which artifacts will be pushed to Fury. Since Fury will be used exclusively for dep/rpm artifacts, by using the id related to them we will skip artifacts which are generated in the build section of goreleaser (aka archives).

# .goreleaser.yml file
  - id: packages # here we say that artifacts built with nfpm will be identified with `packages` string.
    file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"

Step 3: Add custom publisher#

Now we need to tell Goreleaser to actually push those deb/rpm files it produced to a Fury repo. This is easily done with the custom publishers feature.

  - name:
    # by specifying `packages` id here goreleaser will only use this publisher
    # with artifacts identified by this id
      - packages
    dir: "{{ dir .ArtifactPath }}"
    cmd: curl -F package=@{{ .ArtifactName }} https://{{ .Env.FURY_TOKEN }}<your_username>/ #(1)!
  1. Do not forget to fill in your user name.

Look how easy it is. Now on every goreleaser' build, artifacts from nfpm will be concurrently uploaded to Fury and immediately available to the users of those Apt/Yum repositories. Do note, that by default pushed artifacts have a private scope, so don't forget to visit Fury' account dashboard and make them public.

Did I say that Goreleaser is a great tool? I bet I did, so consider supporting it if you have a chance.