Repository: wagoodman/dive (language: go)

Issue:
Publish dive to ghcr.io
**What happened**:

I tried out:

```
docker pull ghcr.io/wagoodman/dive
```

and got this response:

```
Error response from daemon: Head "https://ghcr.io/v2/wagoodman/dive/manifests/latest": denied
```

**What you expected to happen**:

The image to be pulled.

**How to reproduce it (as minimally and precisely as possible)**:

```
docker pull ghcr.io/wagoodman/dive
```

**Anything else we need to know?**:

Opening https://ghcr.io/wagoodman/dive in a browser seems to indicate these packages have been removed or possibly become private.

**Environment**:
- OS version - macOS 15.3.2
- Docker version (if applicable):
```
Client:
 Version:           28.0.1
 API version:       1.48
 Go version:        go1.23.6
 Git commit:        068a01e
 Built:             Wed Feb 26 10:38:16 2025
 OS/Arch:           darwin/arm64
 Context:           desktop-linux

Server: Docker Desktop 4.39.0 (184744)
 Engine:
  Version:          28.0.1
  API version:      1.48 (minimum version 1.24)
  Go version:       go1.23.6
  Git commit:       bbd0a17
  Built:            Wed Feb 26 10:40:57 2025
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.7.25
  GitCommit:        bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
 runc:
  Version:          1.2.4
  GitCommit:        v1.2.4-0-g6c52b3f
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```



Discussion / hints:
This might be a result of merging back changes from my fork (https://github.com/wagoodman/dive/pull/570) which used GHCR to host its container images.

https://github.com/joschi/dive/pkgs/container/dive
[Github Packages - Pushing container images](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pushing-container-images):

> _The easiest way to connect a repository to a container package is to publish the package from a workflow using `${{secrets.GITHUB_TOKEN}}`, as the repository that contains the workflow is linked automatically._

> _To connect a repository when publishing an image from the command line, and to ensure your `GITHUB_TOKEN` has appropriate permissions when using a GitHub Actions workflow, we recommend adding the label `org.opencontainers.image.source` to your `Dockerfile`._

---

**EDIT:** Oh I only just spotted that #570 switched [from DockerHub](https://github.com/wagoodman/dive/pull/570/files#diff-e426ed45842837026e10e66af23d9c7077e89eacbe6958ce7cb991130ad05adaL101-L105) to [using GHCR](https://github.com/wagoodman/dive/pull/570/files#diff-e426ed45842837026e10e66af23d9c7077e89eacbe6958ce7cb991130ad05adaR84-R88).

I initially thought GHCR was in use here and had disappeared from #570 triggering something, but I couldn't find a related workflow trigger and nothing stood out really that would have had that effect. Closest was the usage of [`github.actor` for login](https://github.com/wagoodman/dive/pull/574).

I see that your change also will introduce [`-amd64` / `-arm64` image tags](https://github.com/wagoodman/dive/pull/570/files#diff-7326b55c062b0f46fe9e39aace0a25f4515cf206040fb91a6fd2cae839f5e826R81-R89) for some reason instead of just using multi-arch? (_which is also published_).

I am not familiar with GoReleaser, but the official `docker/build-push-action` can do multi-arch builds and handles the manifest itself. No need for intermediary image tags.

---

Minor concerns raised aside, all @wagoodman needs to do is make a new release and all that would be resolved? Should the release tag skip some versions to align with the @joschi fork, or would it increment to `v0.13.0`?




> Opening https://ghcr.io/wagoodman/dive in a browser seems to indicate these packages have been removed or possibly become private.

In the meantime, either use:
- `wagoodman/dive:latest` (_the old DockerHub release_)
- `ghcr.io/joschi/dive:latest` (_fork that was merged back into this repo recently_)
I've updated the references to the original `docker.io/wagoodman/dive` and also published the images to `ghcr.io/wagoodman/dive`. I still need to update the release pipeline and goreleaser configuration to automate this for the next release.
Below is regarding observed differences in tagging convention since the fork sync. I doubt it'll matter much to anyone, but figured it was worth pointing out.

---

I still think it's a bit weird to tag the individual images with their arch instead of just using the multi-arch image tag 🤔 

I'm not familiar with GoReleaser that well, but I assume those changes will affect DockerHub too (**EDIT:** [yep](https://hub.docker.com/r/wagoodman/dive/tags)). I guess it's not really causing any issues to justify time addressing.

I know how to manage the build/publishing of `Dockerfile` from Github Actions, but from what I can see the current process is a manual trigger? (`Makefile` => GoReleaser)

> ![Image](https://github.com/user-attachments/assets/489032a0-3c1e-4c80-8745-0eacd9d98fe2)

> ![Image](https://github.com/user-attachments/assets/ead00b88-09d0-4b22-9e7c-cb50816e71a6)

---

What I have noticed is you're no longer publishing semver tags for major + major.minor, only the major.minor.patch. The `v` prefix is also dropped (_although that is how it should be_).

Previous tags (_**NOTE:** `v0` shouldn't be a tag, semver major-zero version isn't meant to have a tag, consider removing that one_)

> ![Image](https://github.com/user-attachments/assets/f76faa00-615e-4d21-be66-63dc5586c81a)

Until reaching a `1.0.0` major release, `major.minor` tags are the only real omission atm. Those can be useful to pin a release while updating by pulling that tag again to get any point releases.

Since this is more of a utility rather than compose service it matters less, most will likely use `:latest` and need to update their local copy of that.
Thanks for the detail -- I'll make certain there are all of the old version tags for the next release 👍

Fix patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index bc132916..d10a1678 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -83,9 +83,6 @@ jobs:
       contents: write
       # for pushing container images
       packages: write
-    env:
-      REGISTRY: ghcr.io
-      IMAGE_NAME: ${{ github.repository }}
     steps:
       - uses: actions/checkout@v4
         with:
@@ -94,12 +91,6 @@ jobs:
       - name: Bootstrap environment
         uses: ./.github/actions/bootstrap
 
-      - name: Set up QEMU
-        uses: docker/setup-qemu-action@v3
-
-      - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@v3
-
       - name: Tag release
         run: |
           git tag ${{ github.event.inputs.version }}
@@ -110,7 +101,7 @@ jobs:
       - name: Login to container registry
         uses: docker/login-action@v3
         with:
-          registry: ${{ env.REGISTRY }}
+          registry: docker.io
           username: ${{ github.repository_owner }}
           password: ${{ secrets.GITHUB_TOKEN }}
 
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index e227b8ec..2b12c2df 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -8,6 +8,11 @@ release:
   # If set to true, will not auto-publish the release. This is done to allow us to review the changelog before publishing.
   draft: false
 
+env:
+  # required to support multi architecture docker builds
+  - DOCKER_CLI_EXPERIMENTAL=enabled
+  - CGO_ENABLED=0
+
 builds:
   - binary: dive
     env:
@@ -20,15 +25,15 @@ builds:
       - amd64
       - arm64
       - ppc64le
-    ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.buildTime={{.Date}}`.
+    ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.buildTime={{.Date}}
 
 brews:
   - repository:
       owner: wagoodman
       name: homebrew-dive
       token: "{{.Env.TAP_GITHUB_TOKEN}}"
-    homepage: "https://github.com/wagoodman/dive/"
-    description: "A tool for exploring layers in a docker image"
+    homepage: &project_url "https://github.com/wagoodman/dive/"
+    description: &description "A tool for exploring layers in a docker image"
 
 archives:
   - format: tar.gz
@@ -39,51 +44,96 @@ archives:
 nfpms:
   - license: MIT
     maintainer: Alex Goodman
-    homepage: https://github.com/wagoodman/dive/
-    description: "A tool for exploring layers in a docker image"
+    homepage: *project_url
+    description: *description
     formats:
       - rpm
       - deb
 
 dockers:
-  - id: docker-amd64
+  # docker.io amd64
+  - &dockerhub_amd64
+    id: docker-amd64
     ids:
       - dive
     use: buildx
     goarch: amd64
     image_templates:
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:latest-amd64'
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:{{ .Version }}-amd64'
+      - docker.io/wagoodman/dive:v{{.Version}}-amd64
     build_flag_templates:
       - "--build-arg=DOCKER_CLI_VERSION={{.Env.DOCKER_CLI_VERSION}}"
+      - "--platform=linux/amd64"
       - "--label=org.opencontainers.image.created={{.Date}}"
       - "--label=org.opencontainers.image.title={{.ProjectName}}"
-      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
-      - "--label=org.opencontainers.image.version={{.Version}}"
+      - "--label=org.opencontainers.image.description=A tool for exploring layers in a docker image"
+      - "--label=org.opencontainers.image.url={{.GitURL}}"
       - "--label=org.opencontainers.image.source={{.GitURL}}"
-      - "--platform=linux/amd64"
-  - id: docker-arm64
+      - "--label=org.opencontainers.image.version={{.Version}}"
+      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
+      - "--label=org.opencontainers.image.licenses=MIT"
+      - "--label=org.opencontainers.image.authors=Alex Goodman <@wagoodman>"
+
+  # docker.io arm64
+  - &dockerhub_arm64
+    id: docker-arm64
     ids:
       - dive
     use: buildx
     goarch: arm64
     image_templates:
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:latest-arm64'
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:{{ .Version }}-arm64'
+      - docker.io/wagoodman/dive:v{{.Version}}-arm64
     build_flag_templates:
       - "--build-arg=DOCKER_CLI_VERSION={{.Env.DOCKER_CLI_VERSION}}"
+      - "--platform=linux/arm64/v8"
       - "--label=org.opencontainers.image.created={{.Date}}"
       - "--label=org.opencontainers.image.title={{.ProjectName}}"
-      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
-      - "--label=org.opencontainers.image.version={{.Version}}"
+      - "--label=org.opencontainers.image.description=A tool for exploring layers in a docker image"
+      - "--label=org.opencontainers.image.url={{.GitURL}}"
       - "--label=org.opencontainers.image.source={{.GitURL}}"
-      - "--platform=linux/arm64/v8"
-docker_manifests:
-  - name_template: '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:latest'
+      - "--label=org.opencontainers.image.version={{.Version}}"
+      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
+      - "--label=org.opencontainers.image.licenses=MIT"
+      - "--label=org.opencontainers.image.authors=Alex Goodman <@wagoodman>"
+
+  # ghcr.io amd64
+  - id: ghcr-amd64
+    <<: *dockerhub_amd64
     image_templates:
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:latest-amd64'
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:latest-arm64'
-  - name_template: '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:{{ .Version }}'
+      - ghcr.io/wagoodman/dive:v{{.Version}}-amd64
+
+  # ghcr.io arm64
+  - id: ghcr-arm64
+    <<: *dockerhub_arm64
     image_templates:
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:{{ .Version }}-amd64'
-      - '{{ envOrDefault "REGISTRY" "docker.io" }}/wagoodman/dive:{{ .Version }}-arm64'
+      - ghcr.io/wagoodman/dive:v{{.Version}}-arm64
+
+docker_manifests:
+  # docker.io manifests
+  - name_template: docker.io/wagoodman/dive:latest
+    image_templates: &dockerhub_images
+      - docker.io/wagoodman/dive:v{{.Version}}-amd64
+      - docker.io/wagoodman/dive:v{{.Version}}-arm64
+
+  - name_template: docker.io/wagoodman/dive:v{{.Major}}
+    image_templates: *dockerhub_images
+
+  - name_template: docker.io/wagoodman/dive:v{{.Major}}.{{.Minor}}
+    image_templates: *dockerhub_images
+
+  - name_template: docker.io/wagoodman/dive:v{{.Version}}
+    image_templates: *dockerhub_images
+
+  # ghcr.io manifests
+  - name_template: ghcr.io/wagoodman/dive:latest
+    image_templates: &ghcr_images
+      - ghcr.io/wagoodman/dive:v{{.Version}}-amd64
+      - ghcr.io/wagoodman/dive:v{{.Version}}-arm64
+
+  - name_template: ghcr.io/wagoodman/dive:v{{.Major}}
+    image_templates: *ghcr_images
+
+  - name_template: ghcr.io/wagoodman/dive:v{{.Major}}.{{.Minor}}
+    image_templates: *ghcr_images
+
+  - name_template: ghcr.io/wagoodman/dive:v{{.Version}}
+    image_templates: *ghcr_images
diff --git a/Makefile b/Makefile
index 69d6f46d..6cbe1678 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,6 @@
 BIN = dive
 TEMP_DIR = ./.tmp
 PWD := ${CURDIR}
-REGISTRY ?= docker.io
 SHELL = /bin/bash -o pipefail
 TEST_IMAGE = busybox:latest
 
@@ -213,7 +212,7 @@ ci-test-docker-image:
 		--rm \
 		-t \
 		-v /var/run/docker.sock:/var/run/docker.sock \
-		'${REGISTRY}/wagoodman/dive:latest-amd64' \
+		'docker.io/wagoodman/dive:latest-amd64' \
 			'${TEST_IMAGE}' \
 			--ci
 
diff --git a/README.md b/README.md
index 9d839cab..a13c42e4 100644
--- a/README.md
+++ b/README.md
@@ -192,6 +192,8 @@ nix-env -iA nixpkgs.dive
 **Docker**
 ```bash
 docker pull docker.io/wagoodman/dive
+# or alternatively
+docker pull ghcr.io/wagoodman/dive
 ```
 
 When running you'll need to include the Docker socket file:


Test patch: