mirror of
https://github.com/stakater/Reloader.git
synced 2026-03-14 07:10:32 +00:00
Compare commits
3 Commits
v1.4.14-al
...
feature/us
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a49672fb1 | ||
|
|
81a7e7ef02 | ||
|
|
c9fb423f8d |
1
.github/workflows/pull_request_docs.yaml
vendored
1
.github/workflows/pull_request_docs.yaml
vendored
@@ -10,6 +10,7 @@ on:
|
||||
- 'Dockerfile-docs'
|
||||
- 'docs-nginx.conf'
|
||||
- 'docs/**'
|
||||
- '!docs/plans/**'
|
||||
- 'theme_common'
|
||||
- 'theme_override'
|
||||
- 'deployments/kubernetes/chart/reloader/README.md'
|
||||
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
app: reloader-reloader
|
||||
spec:
|
||||
containers:
|
||||
- image: "ghcr.io/stakater/reloader:v1.4.14-alpha"
|
||||
- image: "ghcr.io/stakater/reloader:v1.4.14"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: reloader-reloader
|
||||
env:
|
||||
|
||||
@@ -141,7 +141,7 @@ spec:
|
||||
fieldPath: metadata.namespace
|
||||
- name: RELOADER_DEPLOYMENT_NAME
|
||||
value: reloader-reloader
|
||||
image: ghcr.io/stakater/reloader:v1.4.14-alpha
|
||||
image: ghcr.io/stakater/reloader:v1.4.14
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
failureThreshold: 5
|
||||
|
||||
@@ -76,7 +76,7 @@ Note: Rolling upgrade also works in the same way for secrets.
|
||||
|
||||
### Hash Value Computation
|
||||
|
||||
Reloader uses SHA1 to compute hash value. SHA1 is used because it is efficient and less prone to collision.
|
||||
Reloader uses SHA512 to compute hash value. SHA512 is used because it is efficient and less prone to collision.
|
||||
|
||||
## Monitor All Namespaces
|
||||
|
||||
@@ -90,4 +90,4 @@ The output file can then be used to deploy Reloader in specific namespace.
|
||||
|
||||
## Compatibility With Helm Install and Upgrade
|
||||
|
||||
Reloader has no impact on helm deployment cycle. Reloader only injects an environment variable in `deployment`, `daemonset` or `statefulset`. The environment variable contains the SHA1 value of `ConfigMaps` or `Secrets` data. So if a deployment is created using Helm and Reloader updates the deployment, then next time you upgrade the helm release, Reloader will do nothing except changing that environment variable value in `deployment` , `daemonset` or `statefulset`.
|
||||
Reloader has no impact on helm deployment cycle. Reloader only injects an environment variable in `deployment`, `daemonset` or `statefulset`. The environment variable contains the SHA512 value of `ConfigMaps` or `Secrets` data. So if a deployment is created using Helm and Reloader updates the deployment, then next time you upgrade the helm release, Reloader will do nothing except changing that environment variable value in `deployment` , `daemonset` or `statefulset`.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
Reloader is inspired from [`configmapcontroller`](https://github.com/fabric8io/configmapcontroller) but there are many ways in which it differs from `configmapcontroller`. Below is the small comparison between these two controllers.
|
||||
|
||||
| Reloader | ConfigMap |
|
||||
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. |
|
||||
| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` |
|
||||
| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It adds difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. |
|
||||
| Reloader uses SHA1 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
|
||||
| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation |
|
||||
| Reloader | ConfigMap |
|
||||
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Reloader can watch both `Secrets` and `ConfigMaps`. | `configmapcontroller` can only watch changes in `ConfigMaps`. It cannot detect changes in other resources like `Secrets`. |
|
||||
| Reloader can perform rolling upgrades on `deployments` as well as on `statefulsets` and `daemonsets` | `configmapcontroller` can only perform rolling upgrades on `deployments`. It currently does not support rolling upgrades on `statefulsets` and `daemonsets` |
|
||||
| Reloader provides both unit test cases and end to end integration test cases for future updates. So one can make sure that new changes do not break any old functionality. | Currently there are not any unit test cases or end to end integration test cases in `configmap-controller`. It adds difficulties for any additional updates in `configmap-controller` and one can not know for sure whether new changes breaks any old functionality or not. |
|
||||
| Reloader uses SHA512 to encode the change in `ConfigMap` or `Secret`. It then saves the SHA1 value in `STAKATER_FOO_CONFIGMAP` or `STAKATER_FOO_SECRET` environment variable depending upon where the change has happened. The use of SHA1 provides a concise 40 characters encoded value that is very less prone to collision. | `configmap-controller` uses `FABRICB_FOO_REVISION` environment variable to store any change in `ConfigMap` controller. It does not encode it or convert it in suitable hash value to avoid data pollution in deployment. |
|
||||
| Reloader allows you to customize your own annotation (for both `Secrets` and `ConfigMaps`) using command line flags | `configmap-controller` restricts you to only their provided annotation |
|
||||
|
||||
@@ -6,7 +6,7 @@ Reloader and k8s-trigger-controller are both built for same purpose. So there ar
|
||||
|
||||
- Both controllers support change detection in `ConfigMaps` and `Secrets`
|
||||
- Both controllers support deployment `rollout`
|
||||
- Reloader controller use SHA1 for hashing
|
||||
- Reloader controller use SHA512 for hashing
|
||||
- Both controllers have end to end as well as unit test cases.
|
||||
|
||||
## Differences
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// GenerateSHA generates SHA from string
|
||||
func GenerateSHA(data string) string {
|
||||
hasher := sha1.New()
|
||||
_, err := io.WriteString(hasher, data)
|
||||
if err != nil {
|
||||
logrus.Errorf("Unable to write data in hash writer %v", err)
|
||||
}
|
||||
sha := hasher.Sum(nil)
|
||||
return fmt.Sprintf("%x", sha)
|
||||
hash := sha512.Sum512_256([]byte(data))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
// TestGenerateSHA generates the sha from given data and verifies whether it is correct or not
|
||||
func TestGenerateSHA(t *testing.T) {
|
||||
data := "www.stakater.com"
|
||||
sha := "abd4ed82fb04548388a6cf3c339fd9dc84d275df"
|
||||
sha := "2e9aa975331b22861b4f62b7fcc69b63e001f938361fee3b4ed888adf26a10e3"
|
||||
result := GenerateSHA(data)
|
||||
if result != sha {
|
||||
t.Errorf("Failed to generate SHA")
|
||||
@@ -18,11 +18,11 @@ func TestGenerateSHA(t *testing.T) {
|
||||
// This ensures consistent behavior and avoids issues with string matching operations
|
||||
func TestGenerateSHAEmptyString(t *testing.T) {
|
||||
result := GenerateSHA("")
|
||||
expected := "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
expected := "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
|
||||
if result != expected {
|
||||
t.Errorf("Failed to generate SHA for empty string. Expected: %s, Got: %s", expected, result)
|
||||
}
|
||||
if len(result) != 40 {
|
||||
if len(result) != 64 {
|
||||
t.Errorf("SHA hash should be 40 characters long, got %d", len(result))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1981,7 +1981,7 @@ func TestRollingUpgradeForDeploymentWithPatchAndRetryUsingArs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"3c9a892aeaedc759abc3df9884a37b8be5680382\"`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"fd9e71a362056bfa864d9859e12978f893d330ce8cbf09218b25d015770ad91f\"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2964,7 +2964,7 @@ func TestRollingUpgradeForDaemonSetWithPatchAndRetryUsingArs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"314a2269170750a974d79f02b5b9ee517de7f280\"`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"43bf9e30e7c4e32a8f8673c462b86d0b1ac626cf498afdc0d0108e79ebe7ee0c\"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3227,7 +3227,7 @@ func TestRollingUpgradeForStatefulSetWithPatchAndRetryUsingArs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"metadata":{"annotations":{"reloader.stakater.com/last-reloaded-from":`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"f821414d40d8815fb330763f74a4ff7ab651d4fa\"`)
|
||||
assert.Contains(t, string(bytes), `\"hash\":\"6aa837180bdf6a93306c71a0cf62b4a45c2d5b021578247b3b64d5baea2b84d9\"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3607,7 +3607,7 @@ func TestRollingUpgradeForDeploymentWithPatchAndRetryUsingErs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`)
|
||||
assert.Contains(t, string(bytes), `"value":"3c9a892aeaedc759abc3df9884a37b8be5680382"`)
|
||||
assert.Contains(t, string(bytes), `"value":"fd9e71a362056bfa864d9859e12978f893d330ce8cbf09218b25d015770ad91f"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4502,7 +4502,7 @@ func TestRollingUpgradeForDaemonSetWithPatchAndRetryUsingErs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`)
|
||||
assert.Contains(t, string(bytes), `"value":"314a2269170750a974d79f02b5b9ee517de7f280"`)
|
||||
assert.Contains(t, string(bytes), `"value":"43bf9e30e7c4e32a8f8673c462b86d0b1ac626cf498afdc0d0108e79ebe7ee0c"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4737,7 +4737,7 @@ func TestRollingUpgradeForStatefulSetWithPatchAndRetryUsingErs(t *testing.T) {
|
||||
assert.Equal(t, patchtypes.StrategicMergePatchType, patchType)
|
||||
assert.NotEmpty(t, bytes)
|
||||
assert.Contains(t, string(bytes), `{"spec":{"template":{"spec":{"containers":[{"name":`)
|
||||
assert.Contains(t, string(bytes), `"value":"f821414d40d8815fb330763f74a4ff7ab651d4fa"`)
|
||||
assert.Contains(t, string(bytes), `"value":"6aa837180bdf6a93306c71a0cf62b4a45c2d5b021578247b3b64d5baea2b84d9"`)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
252
scripts/release.sh
Executable file
252
scripts/release.sh
Executable file
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO="stakater/Reloader"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
confirm() {
|
||||
local msg="$1"
|
||||
echo -en "${YELLOW}$msg [y/N]:${NC} "
|
||||
read -r answer
|
||||
[[ "$answer" =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 <APP_VERSION> <CHART_VERSION>
|
||||
|
||||
Automates the full Reloader release process.
|
||||
|
||||
Arguments:
|
||||
APP_VERSION Application version without 'v' prefix (e.g. 1.5.0, 1.5.0-alpha)
|
||||
CHART_VERSION Helm chart version (e.g. 2.3.0, 2.3.0-rc.1)
|
||||
|
||||
Prerequisites:
|
||||
- gh CLI authenticated with repo access
|
||||
- git configured with push access to $REPO
|
||||
|
||||
Example:
|
||||
$0 1.5.0 2.3.0
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Input validation ---
|
||||
[[ $# -ne 2 ]] && usage
|
||||
|
||||
APP_VERSION="$1"
|
||||
CHART_VERSION="$2"
|
||||
|
||||
# Strip 'v' prefix if provided
|
||||
APP_VERSION="${APP_VERSION#v}"
|
||||
CHART_VERSION="${CHART_VERSION#v}"
|
||||
|
||||
# Validate semver format (with optional prerelease suffix e.g. 1.5.0-alpha, 1.5.0-rc.1)
|
||||
SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+([-][a-zA-Z0-9.]+)?$'
|
||||
|
||||
if ! [[ "$APP_VERSION" =~ $SEMVER_RE ]]; then
|
||||
error "APP_VERSION '$APP_VERSION' is not valid semver (expected X.Y.Z or X.Y.Z-prerelease)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$CHART_VERSION" =~ $SEMVER_RE ]]; then
|
||||
error "CHART_VERSION '$CHART_VERSION' is not valid semver (expected X.Y.Z or X.Y.Z-prerelease)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check prerequisites
|
||||
if ! command -v gh &> /dev/null; then
|
||||
error "gh CLI is not installed. Install from https://cli.github.com/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! gh auth status &> /dev/null; then
|
||||
error "gh CLI is not authenticated. Run 'gh auth login' first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_BRANCH="release-v${APP_VERSION}"
|
||||
TAG="v${APP_VERSION}"
|
||||
|
||||
info "Release plan:"
|
||||
info " App version: $APP_VERSION (tag: $TAG)"
|
||||
info " Chart version: $CHART_VERSION"
|
||||
info " Release branch: $RELEASE_BRANCH"
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# Phase 1: Create release branch
|
||||
# =============================================================================
|
||||
info "Phase 1: Create release branch '$RELEASE_BRANCH' from master"
|
||||
|
||||
if git ls-remote --heads origin "$RELEASE_BRANCH" | grep -q "$RELEASE_BRANCH"; then
|
||||
warn "Branch '$RELEASE_BRANCH' already exists on remote."
|
||||
if ! confirm "Continue using existing branch?"; then
|
||||
error "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! confirm "Create and push branch '$RELEASE_BRANCH' from master?"; then
|
||||
error "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
git fetch origin master
|
||||
git push origin origin/master:refs/heads/"$RELEASE_BRANCH"
|
||||
info "Branch '$RELEASE_BRANCH' created and pushed."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# Phase 2: Trigger Init Release workflow and merge its PR
|
||||
# =============================================================================
|
||||
info "Phase 2: Trigger Init Release workflow"
|
||||
|
||||
if ! confirm "Trigger 'Init Release' workflow for branch '$RELEASE_BRANCH' with version '$APP_VERSION'?"; then
|
||||
error "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh workflow run init-branch-release.yaml \
|
||||
--repo "$REPO" \
|
||||
-f TARGET_BRANCH="$RELEASE_BRANCH" \
|
||||
-f TARGET_VERSION="$APP_VERSION"
|
||||
|
||||
info "Workflow triggered. Waiting for version bump PR to be created..."
|
||||
|
||||
# Poll for the PR (created by the workflow targeting the release branch)
|
||||
MAX_ATTEMPTS=30
|
||||
SLEEP_INTERVAL=10
|
||||
PR_NUMBER=""
|
||||
|
||||
for i in $(seq 1 $MAX_ATTEMPTS); do
|
||||
PR_NUMBER=$(gh pr list \
|
||||
--repo "$REPO" \
|
||||
--base "$RELEASE_BRANCH" \
|
||||
--search "Bump version to $APP_VERSION" \
|
||||
--json number \
|
||||
--jq '.[0].number // empty' 2>/dev/null || true)
|
||||
|
||||
if [[ -n "$PR_NUMBER" ]]; then
|
||||
info "Found PR #$PR_NUMBER"
|
||||
break
|
||||
fi
|
||||
echo -n "."
|
||||
sleep "$SLEEP_INTERVAL"
|
||||
done
|
||||
|
||||
if [[ -z "$PR_NUMBER" ]]; then
|
||||
error "Timed out waiting for Init Release PR. Check workflow status at:"
|
||||
error " https://github.com/$REPO/actions/workflows/init-branch-release.yaml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
info "PR: https://github.com/$REPO/pull/$PR_NUMBER"
|
||||
|
||||
if ! confirm "Merge PR #$PR_NUMBER (version bump to $APP_VERSION)?"; then
|
||||
error "Aborted. PR is still open: https://github.com/$REPO/pull/$PR_NUMBER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh pr merge "$PR_NUMBER" --repo "$REPO" --merge
|
||||
info "PR #$PR_NUMBER merged."
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# Phase 3: Create GitHub release
|
||||
# =============================================================================
|
||||
info "Phase 3: Create GitHub release '$TAG' targeting '$RELEASE_BRANCH'"
|
||||
info "This will trigger the release workflow (Docker image builds, GoReleaser)."
|
||||
|
||||
if ! confirm "Create GitHub release '$TAG'?"; then
|
||||
error "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh release create "$TAG" \
|
||||
--repo "$REPO" \
|
||||
--target "$RELEASE_BRANCH" \
|
||||
--title "Release $TAG" \
|
||||
--generate-notes
|
||||
|
||||
info "GitHub release created: https://github.com/$REPO/releases/tag/$TAG"
|
||||
info "Release workflow will run in the background."
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# Phase 4: Bump Helm chart and create PR
|
||||
# =============================================================================
|
||||
info "Phase 4: Bump Helm chart version to $CHART_VERSION (appVersion: v$APP_VERSION)"
|
||||
|
||||
HELM_BRANCH="release-helm-chart-v${CHART_VERSION}"
|
||||
|
||||
if ! confirm "Create branch '$HELM_BRANCH', bump chart files, and open PR with 'release/helm-chart' label?"; then
|
||||
error "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create branch from latest master
|
||||
git fetch origin master
|
||||
git checkout -b "$HELM_BRANCH" origin/master
|
||||
|
||||
# Bump Chart.yaml: version and appVersion
|
||||
CHART_FILE="deployments/kubernetes/chart/reloader/Chart.yaml"
|
||||
sed -i "s/^version:.*/version: ${CHART_VERSION}/" "$CHART_FILE"
|
||||
sed -i "s/^appVersion:.*/appVersion: v${APP_VERSION}/" "$CHART_FILE"
|
||||
|
||||
# Bump values.yaml: image.tag
|
||||
VALUES_FILE="deployments/kubernetes/chart/reloader/values.yaml"
|
||||
sed -i "s/^\( tag:\).*/\1 v${APP_VERSION}/" "$VALUES_FILE"
|
||||
|
||||
# Show changes for review
|
||||
info "Changes:"
|
||||
git diff
|
||||
|
||||
git add "$CHART_FILE" "$VALUES_FILE"
|
||||
git commit -m "Bump helm chart to ${CHART_VERSION} and appVersion to v${APP_VERSION}"
|
||||
git push origin "$HELM_BRANCH"
|
||||
|
||||
HELM_PR_URL=$(gh pr create \
|
||||
--repo "$REPO" \
|
||||
--base master \
|
||||
--head "$HELM_BRANCH" \
|
||||
--title "Bump Helm chart to ${CHART_VERSION} (appVersion v${APP_VERSION})" \
|
||||
--body "Bump Helm chart version to ${CHART_VERSION} and appVersion to v${APP_VERSION}." \
|
||||
--label "release/helm-chart")
|
||||
|
||||
HELM_PR_NUMBER=$(echo "$HELM_PR_URL" | grep -o '[0-9]*$')
|
||||
info "Helm chart PR created: $HELM_PR_URL"
|
||||
|
||||
if ! confirm "Merge Helm chart PR #$HELM_PR_NUMBER?"; then
|
||||
error "Aborted. PR is still open: $HELM_PR_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh pr merge "$HELM_PR_NUMBER" --repo "$REPO" --merge
|
||||
info "Helm chart PR #$HELM_PR_NUMBER merged."
|
||||
|
||||
# Return to previous branch
|
||||
git checkout -
|
||||
|
||||
echo ""
|
||||
info "============================================="
|
||||
info "Release $TAG complete!"
|
||||
info "============================================="
|
||||
info ""
|
||||
info "Summary:"
|
||||
info " - Release branch: $RELEASE_BRANCH"
|
||||
info " - GitHub release: https://github.com/$REPO/releases/tag/$TAG"
|
||||
info " - Helm chart: $CHART_VERSION (appVersion: v$APP_VERSION)"
|
||||
info ""
|
||||
info "The release workflow is running in the background."
|
||||
info "Monitor at: https://github.com/$REPO/actions"
|
||||
Reference in New Issue
Block a user