mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-26 04:22:05 +02:00
87aa3b6251
refs #3503 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
402 lines
12 KiB
Markdown
402 lines
12 KiB
Markdown
---
|
|
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](/blog/cloud-native-storage)
|
|
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.
|