[VOL-5495] Add publish/release actions for merge
Signed-off-by: Eric Ball <eball@linuxfoundation.org>
Change-Id: I05ef8897523e7c3d128767c3795b7e11f4b0169a
diff --git a/.github/actions/docker-publish-action/README.md b/.github/actions/docker-publish-action/README.md
new file mode 100644
index 0000000..c82e340
--- /dev/null
+++ b/.github/actions/docker-publish-action/README.md
@@ -0,0 +1,80 @@
+<!--
+SPDX-License-Identifier: Apache-2.0
+SPDX-FileCopyrightText: 2026 The Linux Foundation
+-->
+
+# Docker Publish Action
+
+A composite GitHub Action that builds and pushes Docker images tagged with a branch name and git tags.
+
+## Description
+
+Builds Docker images using `make docker-build` and pushes them with `make docker-push`. Images are tagged with the caller-specified branch name and any git tags pointing at HEAD. Golang-style version tags (e.g., `v1.2.3`) have the leading `v` stripped automatically.
+
+## Usage
+
+```yaml
+- uses: ./.github/actions/docker-publish-action
+ with:
+ docker-registry: "docker.io"
+ docker-repository: "myorg"
+ image-name: "myapp"
+ branch-tag: ${{ github.ref_name }}
+ docker-username: ${{ secrets.DOCKER_USERNAME }}
+ docker-password: ${{ secrets.DOCKER_PASSWORD }}
+```
+
+### Inputs
+
+| Input | Required | Default | Description |
+|-------|----------|---------|-------------|
+| `docker-registry` | No | `docker.io` | Docker registry URL |
+| `docker-repository` | Yes | — | Docker repository prefix |
+| `image-name` | Yes | — | Name of the Docker image |
+| `branch-tag` | Yes | — | Branch name to use as a Docker image tag |
+| `extra-environment-vars` | No | `""` | Extra environment variables for make commands |
+| `docker-username` | Yes | — | Docker registry username |
+| `docker-password` | Yes | — | Docker registry password |
+
+### Example Workflow
+
+```yaml
+name: Publish Docker Image
+
+on:
+ push:
+ branches: [main]
+ tags: ["v*"]
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - uses: ./.github/actions/docker-publish-action
+ with:
+ docker-registry: "docker.io"
+ docker-repository: "voltha"
+ image-name: "voltha-northbound"
+ branch-tag: ${{ github.ref_name }}
+ docker-username: ${{ secrets.DOCKER_USERNAME }}
+ docker-password: ${{ secrets.DOCKER_PASSWORD }}
+```
+
+## How It Works
+
+1. Logs in to the configured Docker registry
+2. Discovers git tags pointing at the current HEAD commit
+3. Runs `make docker-build` with `DOCKER_TAG` set to the `branch-tag` input
+4. Runs `make docker-build` for each git tag (stripping the `v` prefix)
+5. Runs `make docker-push` for the branch tag and each git tag
+6. Logs out of the Docker registry
+
+## Requirements
+
+- The repository must have a `Makefile` with `docker-build` and `docker-push` targets
+- These targets must respect `DOCKER_TAG`, `DOCKER_REGISTRY`, `DOCKER_REPOSITORY`, and `IMAGE_NAME` environment variables
+- The checkout step should use `fetch-depth: 0` to ensure git tags are available
diff --git a/.github/actions/docker-publish-action/action.yaml b/.github/actions/docker-publish-action/action.yaml
new file mode 100644
index 0000000..63e62bd
--- /dev/null
+++ b/.github/actions/docker-publish-action/action.yaml
@@ -0,0 +1,144 @@
+---
+# SPDX-FileCopyrightText: 2026 The Linux Foundation
+# SPDX-License-Identifier: Apache-2.0
+
+name: Docker Publish
+description: "Build and push Docker images tagged with branch name and git tags"
+
+inputs:
+ docker-registry:
+ description: "Docker registry URL"
+ required: false
+ default: "docker.io"
+ docker-repository:
+ description: "Docker repository prefix"
+ required: true
+ image-name:
+ description: "Name of the Docker image"
+ required: true
+ branch-tag:
+ description: "Branch name to use as a Docker image tag"
+ required: true
+ extra-environment-vars:
+ description: "Extra environment variables for make commands"
+ required: false
+ default: ""
+ docker-username:
+ description: "Docker registry username"
+ required: true
+ docker-password:
+ description: "Docker registry password"
+ required: true
+
+runs:
+ using: "composite"
+ steps:
+ - name: Log in to Docker registry
+ uses: docker/login-action@v3
+ with:
+ registry: ${{ inputs.docker-registry }}
+ username: ${{ inputs.docker-username }}
+ password: ${{ inputs.docker-password }}
+
+ - name: Get git tags on HEAD
+ id: git-tags
+ shell: bash
+ run: |
+ set -eu -o pipefail
+ TAGS=$(git tag --points-at HEAD || true)
+ echo "tags<<EOF" >> "$GITHUB_OUTPUT"
+ echo "$TAGS" >> "$GITHUB_OUTPUT"
+ echo "EOF" >> "$GITHUB_OUTPUT"
+
+ - name: Build Docker image with branch tag
+ shell: bash
+ run: |
+ set -eu -o pipefail
+ DOCKER_REGISTRY="${{ inputs.docker-registry }}"
+ DOCKER_REPOSITORY="${{ inputs.docker-repository }}"
+ IMAGE_NAME="${{ inputs.image-name }}"
+ BRANCH_NAME="${{ inputs.branch-tag }}"
+
+ echo "Building image with branch tag: ${BRANCH_NAME}"
+ ${{ inputs.extra-environment-vars }} \
+ DOCKER_TAG="${BRANCH_NAME}" \
+ DOCKER_REGISTRY="${DOCKER_REGISTRY}" \
+ DOCKER_REPOSITORY="${DOCKER_REPOSITORY}" \
+ IMAGE_NAME="${IMAGE_NAME}" \
+ make docker-build
+
+ - name: Build Docker images for git tags
+ shell: bash
+ run: |
+ set -eu -o pipefail
+ DOCKER_REGISTRY="${{ inputs.docker-registry }}"
+ DOCKER_REPOSITORY="${{ inputs.docker-repository }}"
+ IMAGE_NAME="${{ inputs.image-name }}"
+
+ TAGS='${{ steps.git-tags.outputs.tags }}'
+ if [ -z "$TAGS" ]; then
+ echo "No git tags on HEAD, skipping tag builds"
+ exit 0
+ fi
+
+ while IFS= read -r tag; do
+ [ -z "$tag" ] && continue
+ # Strip leading 'v' from golang-style version tags
+ DOCKER_TAG="${tag#v}"
+ echo "Building image with tag: ${DOCKER_TAG}"
+ ${{ inputs.extra-environment-vars }} \
+ DOCKER_TAG="${DOCKER_TAG}" \
+ DOCKER_REGISTRY="${DOCKER_REGISTRY}" \
+ DOCKER_REPOSITORY="${DOCKER_REPOSITORY}" \
+ IMAGE_NAME="${IMAGE_NAME}" \
+ make docker-build
+ done <<< "$TAGS"
+
+ - name: Push Docker image with branch tag
+ shell: bash
+ run: |
+ set -eu -o pipefail
+ DOCKER_REGISTRY="${{ inputs.docker-registry }}"
+ DOCKER_REPOSITORY="${{ inputs.docker-repository }}"
+ IMAGE_NAME="${{ inputs.image-name }}"
+ BRANCH_NAME="${{ inputs.branch-tag }}"
+
+ echo "Pushing image with branch tag: ${BRANCH_NAME}"
+ ${{ inputs.extra-environment-vars }} \
+ DOCKER_TAG="${BRANCH_NAME}" \
+ DOCKER_REGISTRY="${DOCKER_REGISTRY}" \
+ DOCKER_REPOSITORY="${DOCKER_REPOSITORY}" \
+ IMAGE_NAME="${IMAGE_NAME}" \
+ make docker-push
+
+ - name: Push Docker images for git tags
+ shell: bash
+ run: |
+ set -eu -o pipefail
+ DOCKER_REGISTRY="${{ inputs.docker-registry }}"
+ DOCKER_REPOSITORY="${{ inputs.docker-repository }}"
+ IMAGE_NAME="${{ inputs.image-name }}"
+
+ TAGS='${{ steps.git-tags.outputs.tags }}'
+ if [ -z "$TAGS" ]; then
+ echo "No git tags on HEAD, skipping tag pushes"
+ exit 0
+ fi
+
+ while IFS= read -r tag; do
+ [ -z "$tag" ] && continue
+ # Strip leading 'v' from golang-style version tags
+ DOCKER_TAG="${tag#v}"
+ echo "Pushing image with tag: ${DOCKER_TAG}"
+ ${{ inputs.extra-environment-vars }} \
+ DOCKER_TAG="${DOCKER_TAG}" \
+ DOCKER_REGISTRY="${DOCKER_REGISTRY}" \
+ DOCKER_REPOSITORY="${DOCKER_REPOSITORY}" \
+ IMAGE_NAME="${IMAGE_NAME}" \
+ make docker-push
+ done <<< "$TAGS"
+
+ - name: Log out of Docker registry
+ if: always()
+ shell: bash
+ run: docker logout "${{ inputs.docker-registry }}"