Skip to content

Publish a release with its assets

Goal: your release appears with its binaries already attached, rather than appearing empty and filling in while the build runs.

For a repository whose releases carry binaries. A library — whose release is a tag, a changelog and nothing to attach — needs none of this and should skip it.

You need the component already working and a build that runs on tags.

1. Upload the artefacts somewhere the release can point at

Your build has to put the bytes somewhere before anything links to them, and it has to do that without needing a release to exist.

With goreleaser, that is an uploads: pipe, which is independent of its release step:

# .goreleaser.yaml
release:
  disable: true

uploads:
  - name: gitlab-generic
    target: '{{ .Env.CI_API_V4_URL }}/projects/{{ .Env.CI_PROJECT_ID }}/packages/generic/{{ .ProjectName }}/{{ .Version }}/{{ .ArtifactName }}'
    method: PUT
    mode: archive
    checksum: true
    signature: true
    custom_headers:
      JOB-TOKEN: '{{ .Env.CI_JOB_TOKEN }}'

disable: true, not skip_upload. The upload still has to happen — it just happens through the pipe above, which does not need a release. That independence is the whole mechanism.

checksum and signature are on because those belong on a release as much as the archives do.

2. Turn assets on in the component

include:
  - component: gitlab.com/phpboyscout/cicd/[email protected]
    inputs:
      assets: true

That changes two things:

  • colophon-publish on your default branch now tags and stops
  • colophon-release runs on the tag pipeline, after your build, and creates the release carrying links to what was uploaded

3. Make the two agree about where the bytes are

The component's asset_base must match your build's upload target. It defaults to the GitLab generic package registry path, which matches the goreleaser snippet above.

If you changed either, change both:

      asset_base: "$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/generic/my-tool/$COLOPHON_VERSION"

This is written twice on purpose. colophon does not derive it from your build's configuration, because doing so would put one tool's settings inside another — and written twice, a mismatch is a configuration error you can see rather than a release full of links that return 404.

$COLOPHON_VERSION is the tag without its leading v.

Check it worked

Cut a release and fetch an asset, rather than counting them:

curl -sIL "$(glab api "projects/$ENC/releases/v1.2.3" \
  | jq -r '.assets.links[0].url')" | head -1

Counting assets is no longer the check worth making. A release whose uploads failed carries a full set of links to files that are not there — so a count passes on exactly the failure this feature exists to prevent. Colophon verifies every asset before publishing, and this is how you confirm that from outside.

If a forge cannot do it

Not every platform can publish a release complete. Where one cannot, colophon creates the release without the guarantee and says so in the job output rather than quietly pretending. A release without the guarantee still beats no release; a silent one would be worse than either.