Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/workflows/image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ on:
branches:
- develop
- 'release/**'
tags:
- 'v[0-9]+.[0-9]+.[0-9]+**'
workflow_call:
inputs:
tag:
description: 'Tag to be released (e.g. v4.2.0)'
required: true
type: string

env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
CI: 1
TAG: ${{ inputs.tag }}

jobs:
image-build-push:
Expand All @@ -32,5 +37,16 @@ jobs:
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push the release images
run: ./scripts/release.sh
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
./scripts/release.sh --tag ${{ inputs.tag }} --registry ghcr.io/openebs/mayastor/dev
elif [[ "${{ github.event_name }}" == "push" ]]; then
./scripts/release.sh
fi
71 changes: 71 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Release Tagging Workflow

on:
release:
types: [ created ]

jobs:
preflight-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive

- uses: cachix/[email protected]
- name: Pre-populate nix-shell
run: |
export NIX_PATH=nixpkgs=$(jq '.nixpkgs.url' nix/sources.json -r)
echo "NIX_PATH=$NIX_PATH" >> $GITHUB_ENV
nix-shell --pure --run "echo" ./scripts/staging/shell.nix

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Validate if the release should be even made
run: |
nix-shell --pure --run "./scripts/staging/validate.sh \
--tag ${{ github.ref_name }} \
--type release" ./scripts/staging/shell.nix

release-images:
runs-on: ubuntu-latest
needs: preflight-checks
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive

- uses: cachix/[email protected]
- name: Pre-populate nix-shell
run: |
export NIX_PATH=nixpkgs=$(jq '.nixpkgs.url' nix/sources.json -r)
echo "NIX_PATH=$NIX_PATH" >> $GITHUB_ENV
nix-shell --pure --run "echo" ./scripts/staging/shell.nix

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Mirror images from dev to Docker Hub
run: |
nix-shell --pure --run "./scripts/staging/mirror-images.sh \
--source ghcr.io/${{ github.repository_owner }}/dev \
--target docker.io/${{ github.repository_owner }} \
--tag ${{ github.ref_name }}" ./scripts/staging/shell.nix
49 changes: 49 additions & 0 deletions .github/workflows/staging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Staging Release

on:
workflow_dispatch:
inputs:
tag:
description: 'Tag to be released (e.g. v4.2.0)'
required: true
type: string

env:
TAG: ${{ inputs.tag }}
CI: 1

jobs:
preflight-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive

- uses: cachix/[email protected]
- name: Pre-populate nix-shell
run: |
export NIX_PATH=nixpkgs=$(jq '.nixpkgs.url' nix/sources.json -r)
echo "NIX_PATH=$NIX_PATH" >> $GITHUB_ENV
nix-shell --pure --run "echo" ./scripts/staging/shell.nix

- name: Login to
uses: docker/login-action@v3
with:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: Validate if the staging should be even made
run: |
nix-shell --pure --keep CI --run "./scripts/staging/validate.sh \
--tag ${TAG} \
--type staging" ./scripts/staging/shell.nix

build-images:
uses: ./.github/workflows/image.yml
needs: preflight-checks
with:
tag: ${{ inputs.tag }}
secrets: inherit
25 changes: 25 additions & 0 deletions scripts/staging/log.sh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With new dependencies module : #1918
We can take this from utils/dependencies instead

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash

# Write output to error output stream.
log_to_stderr() {
echo -e "${1}" >&2
}

log_error() {
log_to_stderr "ERROR: $1"
}

log_warn() {
log_to_stderr "WARNING: $1"
}

# Exit with error status and print error.
log_fatal() {
local -r _return="${2:-1}"
log_error "$1"
exit "${_return}"
}

log() {
echo -e "${1}"
}
61 changes: 61 additions & 0 deletions scripts/staging/mirror-images.sh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also we could move this to dependencies?

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash

# Mirror container images from source registry to target registry using crane.
# Preserves multi-platform support and image digests.

set -euo pipefail

SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]:-"$0"}")")"
ROOT_DIR="${SCRIPT_DIR}/../.."

# if PARENT_ROOT_DIR is not defined use the one below
: "${PARENT_ROOT_DIR:=$ROOT_DIR}"

source "$PARENT_ROOT_DIR/scripts/utils/log.sh"
NO_RUN=true . "$PARENT_ROOT_DIR/scripts/release.sh"

IMAGES=()
for name in $DEFAULT_IMAGES; do
image=$($NIX_EVAL -f "$PARENT_ROOT_DIR" "images.$BUILD_TYPE.$name.imageName" --raw --quiet --argstr product_prefix "$PRODUCT_PREFIX")
IMAGES+=("${image##*/}")
done

SOURCE=""
TARGET=""
TAG=""

while [[ $# -gt 0 ]]; do
case $1 in
--source)
SOURCE="$2"
shift 2
;;
--target)
TARGET="$2"
shift 2
;;
--tag)
TAG="$2"
shift 2
;;
*)
log_fatal "Unknown option: $1"
;;
esac
done

if [[ -z "$SOURCE" ]] || [[ -z "$TARGET" ]] || [[ -z "$TAG" ]]; then
log_fatal "Usage: $0 --source <source> --target <target> --tag <tag>"
fi

echo "Mirroring images from ${SOURCE} to ${TARGET} with tag ${TAG}"

for IMAGE in "${IMAGES[@]}"; do
echo "Mirroring ${IMAGE}:${TAG}..."

SRC="${SOURCE}/${IMAGE}:${TAG}"
DEST="${TARGET}/${IMAGE}:${TAG}"
crane copy --platform all "${SRC}" "${DEST}"

echo "✓ Successfully mirrored ${IMAGE}:${TAG}"
done
20 changes: 20 additions & 0 deletions scripts/staging/shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{ pkgs ? import (import ../../nix/sources.nix).nixpkgs {
overlays = [ (_: _: { inherit (import ../../nix/sources.nix); }) (import ../../nix/overlay.nix { }) ];
}
}:
pkgs.mkShellNoCC {
name = "staging-shell";
buildInputs = with pkgs; [
oras
crane
yq-go
jq
] ++ pkgs.lib.optional (builtins.getEnv "IN_NIX_SHELL" == "pure" && pkgs.system != "aarch64-darwin") [
docker
git
curl
nix
kubernetes-helm-wrapped
cacert
];
}
105 changes: 105 additions & 0 deletions scripts/staging/validate.sh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if the entire staging actually can move to dependencies?
CC @Abhinandan-Purkait

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of doing so ..but the validate script will differ slightly in extensions as it also has to validate charts. Here and in CP there are just images (no charts)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can make the script accept parameters for example; if not specified then it'd do images only

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]:-"$0"}")")"
ROOT_DIR="${SCRIPT_DIR}/../.."
: "${PARENT_ROOT_DIR:=$ROOT_DIR}"

source "$PARENT_ROOT_DIR/scripts/staging/log.sh"

# --- Run release.sh in subshell so it resolves SOURCE_REL correctly ---
(
export NO_RUN=true
export CI=1 # avoid unbound variable errors and skip submodule update in CI
echo "📦 Running release.sh from: $PARENT_ROOT_DIR/scripts/release.sh"
bash "$PARENT_ROOT_DIR/scripts/release.sh"
)


DOCKERHUB_ORG="${DOCKERHUB_ORG:-openebs}"
IMAGE_REGISTRY="${IMAGE_REGISTRY:-docker.io}"

TRIGGER=""
TAG=""

while [[ $# -gt 0 ]]; do
case $1 in
--trigger|--type) TRIGGER="$2"; shift 2 ;;
--tag) TAG="$2"; shift 2 ;;
-h|--help)
cat <<EOF
Usage: $0 --trigger <trigger> [--tag <tag>]
Options:
--trigger <type> release, staging, develop, prerelease
--type <type> Alias for --trigger
--tag <tag> Release tag (e.g., v2.9.0)
EOF
exit 0 ;;
*) log_fatal "Unknown option $1" ;;
esac
done

echo "Validating trigger: $TRIGGER"

case "$TRIGGER" in
release|staging|develop|prerelease)
echo "✅ Valid trigger: $TRIGGER"
;;
*)
log_fatal "❌ Error: Invalid trigger '$TRIGGER'."
;;
esac

echo "Validating tag: $TAG"

case "$TRIGGER" in
release|staging)
[[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]] \
|| log_fatal "❌ Tag must be in format vX.Y.Z or vX.Y.Z-rc.N"
;;
develop)
[[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-develop$ ]] \
|| log_fatal "❌ Tag must be in format vX.Y.Z-develop"
;;
prerelease)
[[ "$TAG" == "v0.0.0" ]] \
|| log_fatal "❌ For prerelease builds, tag must be exactly v0.0.0"
;;
esac

echo "✅ Tag validation passed"

# --- Image Validation Section ---
VERSION="${TAG#v}"

dockerhub_tag_exists() {
local repository="$1" tag="$2"
curl --silent -f -lSL "https://hub.docker.com/v2/repositories/${repository#docker.io/}/tags/${tag}" >/dev/null 2>&1
}

check_images() {
if [[ -n "${DEFAULT_IMAGES:-}" ]]; then
for name in $DEFAULT_IMAGES; do
image=$($NIX_EVAL -f "$PARENT_ROOT_DIR" "images.$BUILD_TYPE.$name.imageName" --raw --quiet --argstr product_prefix "$PRODUCT_PREFIX")
image_name="${image##*/}"
if dockerhub_tag_exists "${DOCKERHUB_ORG}/${image_name}" "${TAG}"; then
log_fatal "❌ Image ${DOCKERHUB_ORG}/${image_name}:${TAG} already exists"
else
echo "✅ Image ${DOCKERHUB_ORG}/${image_name}:${TAG} does not exist"
fi
done
else
echo "⚠️ No DEFAULT_IMAGES defined — skipping image existence checks."
fi
}

case "$TRIGGER" in
staging|release)
check_images
;;
develop|prerelease)
echo "Skipping image checks for $TRIGGER"
;;
esac

echo "✅ All validations completed successfully"