1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-04-11 11:42:15 +02:00

docs(blog): import more posts

refs #3503

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
Carlos Alexandro Becker 2024-02-04 17:22:13 -03:00
parent 3779dfd6a6
commit 29d55a74f8
No known key found for this signature in database
3 changed files with 851 additions and 0 deletions

View File

@ -0,0 +1,316 @@
---
date: 2022-02-05
slug: cloud-native-storage
categories:
- tutorials
authors:
- dirien
---
# How to use GoReleaser with Cloud Native Storage
In this tutorial, I want to describe, how quickly we can deploy our release
artefacts to a cloud native storage when using GoReleaser.
It’s just a few additional lines in your `.goreleaser.yaml`.
<!-- more -->
To better show this, I created a little demo and use the storage services of the
big three cloud providers: Azure Blob Storage, AWS S3 and Google Cloud Storage.
![](https://cdn-images-1.medium.com/max/2000/1*4kvgGvBM9--v2rS7nO5c1g.png)
You can use any S3 compatible storage provider too.
**GoReleaser** support this too! The most prominent (self-hosted) solution is
**MinIO**.
![](https://cdn-images-1.medium.com/max/4802/1*SH5PQKBDEB0M8mAY7EONeQ.png)
## The infrastructure code
I created a very simple **Terraform** deployment to provision on all three cloud
provider their appropriate cloud storage service.
It’s a demo, why not?
You don’t need to use **Terraform** for this, you could use any other means like
**Pulumi**, **CLI** or even the **UI**.
###### `main.tf`
```terraform
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "4.9.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "2.94.0"
}
aws = {
source = "hashicorp/aws"
version = "3.74.0"
}
}
}
provider "azurerm" {
features {}
}
provider "google" {
credentials = file(var.gcp_auth_file)
project = var.gcp_project
region = var.gcp_region
}
provider "aws" {
region = var.aws_region
}
```
###### `variables.tf`
```terraform
variable "gcp_project" {
type = string
}
variable "gcp_region" {
default = "europe-west6"
}
variable "gcp_zone" {
default = "europe-west6-a"
}
variable "gcp_bucket_location" {
default = "EU"
}
variable "gcp_auth_file" {
default = "./auth.json"
description = "Path to the GCP auth file"
}
variable "aws_region" {
default = "eu-central-1"
}
variable "azure_location" {
default = "West Europe"
}
variable "name" {
default = "gorleaser-quickbites"
}
```
###### `blob.tf`
```terraform
resource "google_storage_bucket" "goreleaser-gcp-storage-bucket" {
name = var.name
location = var.gcp_bucket_location
force_destroy = true
uniform_bucket_level_access = false
}
resource "google_storage_bucket_access_control" "goreleaser-gcp-storage-bucket-access-control" {
bucket = google_storage_bucket.goreleaser-gcp-storage-bucket.name
role = "READER"
entity = "allUsers"
}
resource "azurerm_resource_group" "goreleaser-azure-resource-group" {
name = var.name
location = var.azure_location
}
resource "azurerm_storage_account" "goreleaser-azure-storage-account" {
name = "gorleaserquickbites"
resource_group_name = azurerm_resource_group.goreleaser-azure-resource-group.name
location = azurerm_resource_group.goreleaser-azure-resource-group.location
account_tier = "Standard"
account_replication_type = "LRS"
allow_blob_public_access = true
network_rules {
default_action = "Allow"
}
}
resource "azurerm_storage_container" "goreleaser-storage-container" {
name = var.name
storage_account_name = azurerm_storage_account.goreleaser-azure-storage-account.name
container_access_type = "container"
}
resource "aws_s3_bucket" "goreleaser-s3-bucket" {
bucket = var.name
acl = "public-read"
}
```
###### Apply the Terraform script:
```bash
terraform apply -var "gcp_project=xxx"
```
```
...
azurerm_storage_container.goreleaser-storage-container: Creation complete after 0s [id=https://gorleaserquickbites.blob.core.windows.net/gorleaser-quickbites]
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
aws-s3-bucket-name = "gorleaser-quickbites"
azure-storage-account-key = <sensitive>
azure-storage-account-name = "export AZURE_STORAGE_ACCOUNT=gorleaserquickbites"
gcp-bucket-url = "gs://gorleaser-quickbites"
```
###### Run this command
```bash
terraform output azure-storage-account-key
```
to get the Azure Storage Account Key, as it is a output field with sensitive data in it.
```bash
export AZURE_STORAGE_KEY=xxxx
```
Now we can add in our `.goreleaser.yaml` the new **blobs** field.
Important is here to set the right provider: **gs** (for Google Cloud Storage),
**azblob** (for Azure Blob) and **s3** (for AWS S3 or compatible provider)!
```yaml
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- darwin
release:
disable: true
---
blobs:
- provider: gs
bucket: gorleaser-quickbites
- provider: azblob
bucket: gorleaser-quickbites
- provider: s3
bucket: gorleaser-quickbites
region: eu-central-1
```
In this demo, I disabled the **release **section, as I don’t want to upload to
GitHub.
## Authentication
In terms of authentication the GoReleaser’s blob pipe authentication varies depending upon the blob provider as mentioned below:
### S3 Provider
S3 provider support AWS [default credential
provider](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials)
chain in the following order:
- Environment variables.
- Shared credentials file.
- If your application is running on an Amazon EC2 instance, IAM role for Amazon EC2.
### Azure Blob Provider Currently it supports authentication only
with [environment variables](https://docs.microsoft.com/en-us/azure/storage/common/storage-azure-cli#set-default-azure-storage-account-environment-variables):
- AZURE_STORAGE_ACCOUNT
- AZURE_STORAGE_KEY or AZURE_STORAGE_SAS_TOKEN
### GCS
Provider GCS provider uses [Application Default
Credentials](https://cloud.google.com/docs/authentication/production) in the
following order:
- Environment Variable (GOOGLE_APPLICATION_CREDENTIALS)
- Default Service Account from the compute instance (Compute Engine, Kubernetes
Engine, Cloud function etc).
## Run GoReleaser
After configuring we can finally execute **GoReleaser**, in your pipeline code
via the command:
```bash
goreleaser release --rm-dist
```
If everything went smooth, you should see a similar output, showing the upload of your artefacts.
```
...
• publishing
• blobs
• uploading path=quick-bites/0.1/quick-bites_0.1_checksums.txt
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_amd64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_amd64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_386.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_checksums.txt
• uploading path=quick-bites/0.1/quick-bites_0.1_checksums.txt
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_386.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_amd64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_amd64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_amd64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_386.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_linux_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_arm64.tar.gz
• uploading path=quick-bites/0.1/quick-bites_0.1_darwin_amd64.tar.gz
• release succeeded after 22.63s
...
```
> One note: The provider fails silently, if your credentials are wrong. You
> would still see uploading and release succeeded. Keep this in mind, if the
> files are not appearing in the UI. I wasted some time on this. The culprit is
> the underlying library GoReleaser is using.
Let’s check in the consoles of the cloud provider too, If the files are present.
###### Google Cloud Storage:
![Google Cloud Storage](https://cdn-images-1.medium.com/max/2468/1*OHPaMIOK2YP7HsdgXEPpSw.png)
###### Azure Blob Storage
![Azure Blob Storage](https://cdn-images-1.medium.com/max/2792/1*K0BMoKe2qH29YHCOtZ8e9A.png)
###### AWS S3
![AWS S3](https://cdn-images-1.medium.com/max/2868/1*mvgyZMWtZseRabusw_R4Dg.png)
Looks very good! Now you can share the URLs of the files for further use!
## Want more Informations?
If you want to know more about some advanced options, feel free to check out the
[official documentation about the blob support in
GoReleaser](https://goreleaser.com/customization/blob/)
And here is the example code: [dirien/quick-bytes](https://github.com/dirien/quick-bites/tree/main/goreleaser-blob)
![Have fun](https://cdn-images-1.medium.com/max/2000/0*kbicxfar7Vo9rUon.jpg)

View File

@ -0,0 +1,402 @@
---
date: 2022-02-20
slug: azure-devops
categories:
- tutorials
authors:
- dirien
---
# Use GoReleaser With Azure DevOps
In this blog article, I want to show how to use **GoReleaser** in **Azure DevOps**.
<!-- more -->
![](https://cdn-images-1.medium.com/max/2000/1*hAK9NMa-YbSnTQdSEoX7Gw.png)
In this blog article, I want to show how to use **GoReleaser** in **Azure
DevOps**.
### But why? Are not everyone using GitHub?
Exactly, not everyone is using GitHub. Actually, there are many companies who
use the Azure Cloud with **Azure DevOps**.
## What is Azure DevOps?
**Azure DevOps** provides developer services for allowing teams to plan work,
collaborate on code development, and build and deploy applications.
**Azure DevOps** provides integrated features that you can access through your
web browser or IDE client. You can use one or more of the following standalone
services based on your business needs:
- **Azure Repos** provides Git repositories.
- **Azure Pipelines** provides build and release services to support continuous
integration and delivery of your applications.
- **Azure Boards** delivers a suite of Agile tools to support planning and
tracking work, code defects, and issues using Kanban and Scrum methods.
- **Azure Test Plans** provides several tools to test your apps, including
manual/exploratory testing and continuous testing.
- **Azure Artifacts** allows teams to share packages such as Maven, npm, NuGet,
and more from public and private sources and integrate package sharing into your
pipelines.
## Install GoReleaser Via The Marketplace
![](https://cdn-images-1.medium.com/max/4144/1*NCY5i6iCEPW5ZpNhYeB6Jg.png)
**GoReleaser** offers a [Plugin via the
Marketplace](https://marketplace.visualstudio.com/items?itemName=GoReleaser.goreleaser).
The installation itself is done via some clicks in the UI and you are ready to
start!
In your pipeline editor you can lookup the task:
![](https://cdn-images-1.medium.com/max/2000/1*U-zVyao5qwgjfzTcGHgSJA.png)
And quickly change the default settings to fit with your use case!
For example set a specific version or execute certain **GoReleaser** commands.
See the official docs for more details
[https://github.com/goreleaser/goreleaser-azure-devops-extension](https://github.com/goreleaser/goreleaser-azure-devops-extension)
![](https://cdn-images-1.medium.com/max/2000/1*Aqtx-0KvADotNmeX7X1HTQ.png)
## Finally The Demo!
```go
package main
import (
"fmt"
)
var (
version = "0.0.1"
commit = "none"
date = "none"
builtBy = "none"
)
func main() {
fmt.Println("Version:\t", version)
fmt.Println("Commit:\t\t", commit)
fmt.Println("Date:\t\t", date)
fmt.Println("Built by:\t", builtBy)
}
```
Before we head over to the configure the pipeline, let us create the
`.goreleaser.yaml`
```yaml
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goarch:
- amd64
- arm64
goos:
- linux
- darwin
project_name: goreleaser-ado
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}-next"
source:
enabled: true
release:
disable: true
sboms:
- artifacts: archive
- id: source
artifacts: source
signs:
- cmd: cosign
certificate: "${artifact}.pem"
args:
- sign-blob
- "-key=cosign.key"
- "--output-certificate=${certificate}"
- "--output-signature=${signature}"
- "${artifact}"
artifacts: checksum
output: true
stdin: "{{ .Env.COSIGN_PASSWORD }}"
docker_signs:
- cmd: cosign
artifacts: images
output: true
args:
- "sign"
- "-key=cosign.key"
- "${artifact}"
stdin: "{{ .Env.COSIGN_PASSWORD }}"
dockers:
- image_templates: ["dirien/{{ .ProjectName }}:{{ .Version }}-amd64"]
goarch: amd64
dockerfile: Dockerfile
use: buildx
build_flag_templates:
- --platform=linux/amd64
- image_templates: ["dirien/{{ .ProjectName }}:{{ .Version }}-arm64"]
goarch: arm64
dockerfile: Dockerfile
use: buildx
build_flag_templates:
- --platform=linux/arm64/v8
docker_manifests:
- name_template: "dirien/{{ .ProjectName }}:{{ .Version }}"
image_templates:
- "dirien/{{ .ProjectName }}:{{ .Version }}-amd64"
- "dirien/{{ .ProjectName }}:{{ .Version }}-arm64"
- name_template: "dirien/{{ .ProjectName }}:latest"
image_templates:
- "dirien/{{ .ProjectName }}:{{ .Version }}-amd64"
- "dirien/{{ .ProjectName }}:{{ .Version }}-arm64"
```
Here, we going to create **linux** and **darwin** binary, the corresponding
container, create the SBoM with syft and sign everything via cosign.
> Here is one first important steps: you need to disable the **release** step in
> GoReleaser.
> Azure DevOps does not work the same way as GitHub what releases concerns.
> We handle the upload of the artefacts differently.
If you need more infos, for the different settings and possibilities inside
**GoReleaser**, head over to the official documentation
[https://goreleaser.com/intro/](https://goreleaser.com/intro/)
### Service
Connection in Azure DevOps As we going to upload the image to Docker Hub, we
need to create in **Azure Devops** the Service Connection.
Go to **Project Settings** and click **Service connections**:
![](https://cdn-images-1.medium.com/max/2000/1*QDD9dVR5ZYUtm4qh5Izy2w.png)
![](https://cdn-images-1.medium.com/max/2000/1*PMGoYUHoda1bVumVGW1Fow.png)
Choose **Docker Registry**:
![](https://cdn-images-1.medium.com/max/2000/1*JmkHy2p5pjhc7llWCHjChw.png)
In the detail view, select **Docker Hub **and then enter your details, like
**Docker ID**, **Docker Password** and the **Service Connection Name**:
![](https://cdn-images-1.medium.com/max/2000/1*WCT6xaaNtoT6Y-Ws7-0qOQ.png)
Click **Verify and save**, we will come back to the service connection in our
Pipeline code.
### The Azure Pipeline File
Now starts the fun part, the creation of the actual Azure Pipeline.
If you are completely new to **Azure DevOps** pipeline, I highly suggest to
checkout the
[docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?view=azure-devops&tabs=java%2Ctfs-2018-2%2Cbrowser)
from Microsoft.
In our example, we going to write the pipeline only as code (there is a
deprecated UI only option too! But meh!).
Azure Pipeline are written in **yaml.**
```yaml
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
pr:
branches:
include:
- main
trigger:
tags:
include:
- "*"
branches:
include:
- "*"
jobs:
- job: build
pool:
vmImage: ubuntu-latest
steps:
- task: GoTool@0
displayName: "Install Go"
inputs:
version: "1.17"
- task: CmdLine@2
displayName: "Build and Test"
inputs:
script: |
go mod tidy
go build .
- job: release
dependsOn: build
displayName: Release via GoReleaser
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))
variables:
- group: cosign
pool:
vmImage: ubuntu-latest
steps:
- task: GoTool@0
displayName: "Install Go"
inputs:
version: "1.17"
- task: CmdLine@2
displayName: "Install Syft"
inputs:
script: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
- task: CmdLine@2
displayName: "Install cosign"
inputs:
script: |
curl -sLO https://github.com/sigstore/cosign/releases/download/v1.5.2/cosign-linux-amd64
chmod +x cosign-linux-amd64
mv cosign-linux-amd64 /usr/local/bin/cosign
- task: Docker@2
inputs:
containerRegistry: "dirien-docker-hub"
command: "login"
addPipelineData: false
addBaseImageData: false
- task: goreleaser@0
inputs:
version: "latest"
distribution: "goreleaser"
args: "release --rm-dist"
- task: CopyFiles@2
displayName: "Copy GoReleaser dist folder to ArtifactStagingDirectory"
inputs:
Contents: |
dist/*.tar.gz
dist/*.zip
dist/*.txt
dist/*.sbom
dist/*.sig
cosign.pub
TargetFolder: "$(Build.ArtifactStagingDirectory)"
CleanTargetFolder: true
OverWrite: true
flattenFolders: true
- task: PublishBuildArtifacts@1
displayName: "Publish GoReleaser release artifacts"
inputs:
ArtifactName: "GoReleaser release"
```
The pipeline consist of two different jobs parts:
- the **build** job, run every time something changes on any branch or when a
pull request gets created. Here we can run our tests, linting, SAST to get
quickly feedback.
- the **release** job, will run only when a git tag gets created (see the
condition tag under the job tag). Creating a git tag is part of the release
process. Similar as we do in the GitHub Flow.
During the release job, we download [Anchore
syft](https://github.com/anchore/syft) and
[cosign](https://github.com/sigstore/cosign) as we going to need them during the
**gorleaser** task.
Currently there is no native task for this in **Azure DevOps**. We just use the
**CmdLine** task and curl the binaries.
![](https://cdn-images-1.medium.com/max/2496/1*O01UvqQCv8255Kj9JEvxiw.png)
It is also important to log into your **Docker Hub** account, via the **Service
Connection** we created earlier.
The **Docker** task takes care of the actual login.
![](https://cdn-images-1.medium.com/max/2000/1*_uMeZymqEJ0Xqq64OP_UXA.png)
Now we can call our **GoReleaser** task.
![](https://cdn-images-1.medium.com/max/2000/1*blEbdGwd8PXZ9ExCScfYtw.png)
### Azure Pipeline Secret Library
For cosign, I use a password, I stored in the Azure Pipeline Library as secret
variable.
![](https://cdn-images-1.medium.com/max/4028/1*ioSS8X6yT4qFNQrCrQbAYA.png)
In my pipeline code, I will pass this value as environment variable via the
variables tag.
![](https://cdn-images-1.medium.com/max/2000/1*CTox6hgrOCgaTs9AFJWUhQ.png)
In this demo, I am going to publish the release artefacts as build artefacts.
![](https://cdn-images-1.medium.com/max/2244/1*nwH4Ej9GbQ6RdE_MfYMelw.png)
The task **CopyFiles** collects some files from the **dist** folder and the
cosign public key and **PublishBuildArtifacts** publish them.
You will find the artefacts on the pipeline detail
![](https://cdn-images-1.medium.com/max/2000/1*GWCiLGBnHOnCjyRuqrPEEw.png)
![](https://cdn-images-1.medium.com/max/4220/1*MLeku1FpKCFMv7bfNvu_eA.png)
Of course, you can use other targets too, like a cloud native storage.
You can check out the
[How to use GoReleaser with Cloud Native
Storage](https://blog.goreleaser.com/how-to-use-goreleaser-with-cloud-native-storage-bbc4bee5fe91)
post for more details on this subject
### Release the kraken äh app!
Head over to **tags** menu and create a new tag in the UI
![](https://cdn-images-1.medium.com/max/2000/1*zIYaYhDk1rSpd5_si5mHIA.png)
![](https://cdn-images-1.medium.com/max/4472/1*Zaq4EUjn3egC5_3VLVQA5Q.png)
Your pipeline should immediately start to run:
![](https://cdn-images-1.medium.com/max/5528/1*h5YYGAPjIXrcympI01H9yA.png)
And both jobs should run:
![](https://cdn-images-1.medium.com/max/5592/1*TawbQohuoGdG4sO9xo0YLw.png)
![](https://cdn-images-1.medium.com/max/2000/0*GY5jcM6UErG39iF2.jpg)
And this is pretty much all of it! As I promised, very easy and straight forward
we can implement **GoReleaser** in **Azure DevOps**, similar we would use it in
GitHub
![](https://cdn-images-1.medium.com/max/2560/0*1ZhRSdH-Se88gOdj.jpg)
### Caveat:
- I use in cosign not the
[keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) approach, as
I am not sure that it will work for **Azure DevOps**. So I generated a keypair
and committed the public and private key into the repository.

View File

@ -0,0 +1,133 @@
---
date: 2022-03-07
slug: homebrew-gofish
categories:
- tutorials
authors:
- dirien
---
# GoReleaser: How To Distribute Your Binaries With Homebrew Or GoFish
This article is going to be a quick bite (or drink)! We going to discover, how
fast we can create a **Homebrew** or **GoFish** deployment of our binaries with
the help of **GoReleaser**.
<!-- more -->
But first, let us take a look into the concepts of the two package managers:
### **Homebrew **🍺
> The Missing Package Manager for macOS (or Linux)
This statement is not from me, but from the official
[Homebrew](https://brew.sh/) website. **Homebrew** is similar to other package
managers, like [apt-get](https://wiki.debian.org/apt-get),
[aptitude](https://wiki.debian.org/Aptitude), or
[dpkg](https://wiki.debian.org/dpkg). I will not go in this article into the
details about **Homebrew**, but some terms are important to understand, as we
going to use them in our `.goreleaser.yaml` file:
**Tap:** A Git repository of packages.
**Formula**: A software package. When we want to install new programs or
libraries, we install a formula.
### GoFish 🐠
> GoFish, the Package Manager 🐠
[GoFish](https://gofi.sh/) is a cross-platform systems package manager, bringing
the ease of use of Homebrew to Linux and Windows. Same as with **Homebrew**, I
am not going into detail of **GoFish** but we need also here some understanding
of the **GoFish** terminology:
**Rig:** A git repository containing fish food.
**Food:** The package definition
### The example code
For each package manager, you should create its own GitHub repository. You can
name it as you please, but i prefer to add the meaning of the repository.
- **goreleaser-rig** for GoFish
- **goreleaser-tap** for Homebrew
Add following snippet for **GoFish** support, to your existing
`.goreleaser.yaml`:
```yaml
rigs:
- rig:
owner: dirien
name: goreleaser-rig
homepage: "https://github.com/dirien/quick-bites"
description: "Different type of projects, not big enough to warrant a separate repo."
license: "Apache License 2.0"
```
And for **Homebrew**, add this little snippet:
```yaml
brews:
- tap:
owner: dirien
name: goreleaser-tap
folder: Formula
homepage: "https://github.com/dirien/quick-bites"
description: "Different type of projects, not big enough to warrant a separate repo."
license: "Apache License 2.0"
```
That’s all for now, and as usual with GoReleaser you can head over to the great
documentation for more advanced settings:
> [https://goreleaser.com](https://goreleaser.com/intro/)
Now run the release process and you will see this in your logs:
```
• homebrew tap formula
• pushing formula=Formula/goreleaser-brew-fish.rb repo=dirien/goreleaser-tap
• gofish fish food cookbook
• pushing food=Food/goreleaser-brew-fish.lua repo=dirien/goreleaser-rig
```
Perfect! Everything works as expected.
We can check the content on the GitHub UI.
![](https://cdn-images-1.medium.com/max/5964/1*O2zfXri4yrmo_GN3clczow.png)
![](https://cdn-images-1.medium.com/max/6020/1*1TVV84tYM1staeDcifH7tw.png)
### Installation
Now we can add the tap and the rig on our clients
**Homebrew**
```bash
brew tap dirien/goreleaser-tap
brew install goreleaser-brew-fish
```
**GoFish**
```bash
gofish rig add https://github.com/dirien/goreleaser-rig
gofish install github.com/dirien/goreleaser-rig/goreleaser-brew-fish
```
### The End
Now you can distribute this tap or rig repositories and everybody can install your projects via this package manager.
![](https://cdn-images-1.medium.com/max/2560/0*prjIhehAsUYTBaLx.jpg)
### The Code
You can find the demo code in my repository, to see some more details:
[dirien/quick-bites](https://github.com/dirien/quick-bites/tree/main/goreleaser-brew-fish).