fix self-hosting
This commit is contained in:
@@ -16,7 +16,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
|
|||||||
### Quickstart
|
### Quickstart
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hosting && ./setup
|
git clone -b self-hosting https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hosting && ./setup
|
||||||
# After setup is complete run `./start` to start OpenPanel
|
# After setup is complete run `./start` to start OpenPanel
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ git clone https://github.com/Openpanel-dev/openpanel && cd openpanel/self-hostin
|
|||||||
<Step>
|
<Step>
|
||||||
### Clone
|
### Clone
|
||||||
|
|
||||||
Clone the repository to your VPS
|
Clone the repository to your VPS and checkout the self-hosting tag
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Openpanel-dev/openpanel.git
|
git clone -b self-hosting https://github.com/Openpanel-dev/openpanel.git
|
||||||
```
|
```
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ export async function bootCron() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (
|
if (process.env.SELF_HOSTED && process.env.NODE_ENV === 'production') {
|
||||||
(process.env.VITE_SELF_HOSTED === 'true' || process.env.SELF_HOSTED) &&
|
|
||||||
process.env.NODE_ENV === 'production'
|
|
||||||
) {
|
|
||||||
jobs.push({
|
jobs.push({
|
||||||
name: 'ping',
|
name: 'ping',
|
||||||
type: 'ping',
|
type: 'ping',
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export async function deleteProjects(job: Job<CronQueuePayload>) {
|
|||||||
|
|
||||||
for (const table of tables) {
|
for (const table of tables) {
|
||||||
const query =
|
const query =
|
||||||
process.env.VITE_SELF_HOSTED === 'true'
|
process.env.SELF_HOSTED === 'true'
|
||||||
? `ALTER TABLE ${table} DELETE WHERE ${where};`
|
? `ALTER TABLE ${table} DELETE WHERE ${where};`
|
||||||
: `ALTER TABLE ${table}_replicated ON CLUSTER '{cluster}' DELETE WHERE ${where};`;
|
: `ALTER TABLE ${table}_replicated ON CLUSTER '{cluster}' DELETE WHERE ${where};`;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function getIsCluster() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getIsSelfHosting() {
|
export function getIsSelfHosting() {
|
||||||
return process.env.VITE_SELF_HOSTED === 'true' || !!process.env.SELF_HOSTED;
|
return process.env.SELF_HOSTED === 'true' || !!process.env.SELF_HOSTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIsDry() {
|
export function getIsDry() {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionStatus: {
|
subscriptionStatus: {
|
||||||
needs: { subscriptionStatus: true, subscriptionCanceledAt: true },
|
needs: { subscriptionStatus: true, subscriptionCanceledAt: true },
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return 'active';
|
return 'active';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ const getPrismaClient = () => {
|
|||||||
hasSubscription: {
|
hasSubscription: {
|
||||||
needs: { subscriptionStatus: true, subscriptionEndsAt: true },
|
needs: { subscriptionStatus: true, subscriptionEndsAt: true },
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionPeriodEventsCountExceededAt: true,
|
subscriptionPeriodEventsCountExceededAt: true,
|
||||||
},
|
},
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ const getPrismaClient = () => {
|
|||||||
isCanceled: {
|
isCanceled: {
|
||||||
needs: { subscriptionStatus: true, subscriptionCanceledAt: true },
|
needs: { subscriptionStatus: true, subscriptionCanceledAt: true },
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionEndsAt: true,
|
subscriptionEndsAt: true,
|
||||||
},
|
},
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionCanceledAt: true,
|
subscriptionCanceledAt: true,
|
||||||
},
|
},
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionPeriodEventsLimit: true,
|
subscriptionPeriodEventsLimit: true,
|
||||||
},
|
},
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionCurrentPeriodStart: {
|
subscriptionCurrentPeriodStart: {
|
||||||
needs: { subscriptionStartsAt: true, subscriptionInterval: true },
|
needs: { subscriptionStartsAt: true, subscriptionInterval: true },
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ const getPrismaClient = () => {
|
|||||||
subscriptionInterval: true,
|
subscriptionInterval: true,
|
||||||
},
|
},
|
||||||
compute(org) {
|
compute(org) {
|
||||||
if (process.env.VITE_SELF_HOSTED === 'true') {
|
if (process.env.SELF_HOSTED === 'true') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ async function createOrGetOrganization(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.env.VITE_SELF_HOSTED !== 'true' && !process.env.SELF_HOSTED) {
|
if (!process.env.SELF_HOSTED) {
|
||||||
await addTrialEndingSoonJob(
|
await addTrialEndingSoonJob(
|
||||||
organization.id,
|
organization.id,
|
||||||
1000 * 60 * 60 * 24 * TRIAL_DURATION_IN_DAYS * 0.9,
|
1000 * 60 * 60 * 24 * TRIAL_DURATION_IN_DAYS * 0.9,
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# Common
|
# Common
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- VITE_SELF_HOSTED=true
|
- SELF_HOSTED=true
|
||||||
# URLs
|
# URLs
|
||||||
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
||||||
- DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
- DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
||||||
@@ -166,7 +166,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# Common
|
# Common
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- VITE_SELF_HOSTED=true
|
- SELF_HOSTED=true
|
||||||
# URLs
|
# URLs
|
||||||
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
||||||
- REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@opkv:6379
|
- REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@opkv:6379
|
||||||
@@ -193,7 +193,7 @@ services:
|
|||||||
- SERVICE_FQDN_OPBULLBOARD
|
- SERVICE_FQDN_OPBULLBOARD
|
||||||
# Common
|
# Common
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- VITE_SELF_HOSTED=true
|
- SELF_HOSTED=true
|
||||||
# URLs
|
# URLs
|
||||||
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
- DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
||||||
- DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
- DATABASE_URL_DIRECT=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@opdb:5432/${OPENPANEL_POSTGRES_DB:-openpanel-db}?schema=public
|
||||||
|
|||||||
@@ -77,6 +77,65 @@ while [[ $# -gt 0 ]]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Check if jq is installed (required for JSON parsing)
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}jq is required but not installed${NC}\n"
|
||||||
|
echo -e "${CYAN}jq is a lightweight JSON processor needed to parse GitHub API responses.${NC}\n"
|
||||||
|
|
||||||
|
# Detect OS and suggest installation
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
. /etc/os-release
|
||||||
|
OS_ID=$ID
|
||||||
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
OS_ID="macos"
|
||||||
|
else
|
||||||
|
OS_ID="unknown"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine installation command
|
||||||
|
case $OS_ID in
|
||||||
|
ubuntu|debian)
|
||||||
|
INSTALL_CMD="sudo apt-get update && sudo apt-get install -y jq"
|
||||||
|
;;
|
||||||
|
rhel|centos|fedora)
|
||||||
|
INSTALL_CMD="sudo yum install -y jq"
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
INSTALL_CMD="sudo apk add --no-cache jq"
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
INSTALL_CMD="brew install jq"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Could not detect your OS.${NC}"
|
||||||
|
echo -e "${YELLOW}Please install jq manually:${NC}"
|
||||||
|
echo -e " ${GREEN}Ubuntu/Debian:${NC} sudo apt-get update && sudo apt-get install -y jq"
|
||||||
|
echo -e " ${GREEN}RHEL/CentOS:${NC} sudo yum install -y jq"
|
||||||
|
echo -e " ${GREEN}Alpine:${NC} sudo apk add --no-cache jq"
|
||||||
|
echo -e " ${GREEN}macOS:${NC} brew install jq"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Ask user if they want to install
|
||||||
|
read -p "$(echo -e ${GREEN}Would you like to install jq now? [Y/n]:${NC} )" -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||||
|
echo -e "${RED}jq is required to continue. Please install it manually.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install jq
|
||||||
|
echo -e "${BLUE}Installing jq...${NC}\n"
|
||||||
|
if eval "$INSTALL_CMD"; then
|
||||||
|
echo -e "\n${GREEN}✓ jq installed successfully!${NC}\n"
|
||||||
|
else
|
||||||
|
echo -e "\n${RED}✗ Failed to install jq. Please install it manually.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if user needs to be logged in (for apply mode)
|
# Check if user needs to be logged in (for apply mode)
|
||||||
if [ "$APPLY_MODE" = true ]; then
|
if [ "$APPLY_MODE" = true ]; then
|
||||||
# Check if Docker is available
|
# Check if Docker is available
|
||||||
@@ -135,11 +194,7 @@ fi
|
|||||||
# List all tags if requested
|
# List all tags if requested
|
||||||
if [ "$LIST_ALL" = true ]; then
|
if [ "$LIST_ALL" = true ]; then
|
||||||
echo -e "${GREEN}All available tags:${NC}\n"
|
echo -e "${GREEN}All available tags:${NC}\n"
|
||||||
if command -v jq &> /dev/null; then
|
echo "$TAGS_JSON" | jq -r '.[] | " \(.name) (\(.commit.sha[0:7]))"'
|
||||||
echo "$TAGS_JSON" | jq -r '.[] | " \(.name) (\(.commit.sha[0:7]))"'
|
|
||||||
else
|
|
||||||
echo "$TAGS_JSON" | grep "\"name\":" | sed 's/.*"name": "\([^"]*\)".*/ \1/'
|
|
||||||
fi
|
|
||||||
echo ""
|
echo ""
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -150,15 +205,9 @@ get_latest_tag() {
|
|||||||
local output_var_tag=$2
|
local output_var_tag=$2
|
||||||
local output_var_sha=$3
|
local output_var_sha=$3
|
||||||
|
|
||||||
if command -v jq &> /dev/null; then
|
# Use jq for JSON parsing
|
||||||
# Use jq for better JSON parsing
|
local tag=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .name" 2>/dev/null)
|
||||||
local tag=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .name" 2>/dev/null)
|
local sha=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .commit.sha" 2>/dev/null)
|
||||||
local sha=$(echo "$TAGS_JSON" | jq -r "[.[] | select(.name | contains(\"${component}\"))] | .[0] | .commit.sha" 2>/dev/null)
|
|
||||||
else
|
|
||||||
# Fallback to grep/sed
|
|
||||||
local tag=$(echo "$TAGS_JSON" | grep -o "\"name\": \"[^\"]*${component}[^\"]*\"" | head -1 | cut -d'"' -f4)
|
|
||||||
local sha=$(echo "$TAGS_JSON" | grep -B5 "\"name\": \"${tag}\"" | grep "\"sha\"" | head -1 | cut -d'"' -f4)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$tag" ] || [ "$tag" == "null" ]; then
|
if [ -z "$tag" ] || [ "$tag" == "null" ]; then
|
||||||
echo -e "${RED}✗${NC} ${component}: No matching tag found"
|
echo -e "${RED}✗${NC} ${component}: No matching tag found"
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ build_image() {
|
|||||||
--platform linux/amd64,linux/arm64 \
|
--platform linux/amd64,linux/arm64 \
|
||||||
-t "$full_version" \
|
-t "$full_version" \
|
||||||
--build-arg DATABASE_URL="postgresql://p@p:5432/p" \
|
--build-arg DATABASE_URL="postgresql://p@p:5432/p" \
|
||||||
--build-arg VITE_SELF_HOSTED="true" \
|
|
||||||
-f "apps/$app/Dockerfile" \
|
-f "apps/$app/Dockerfile" \
|
||||||
--push \
|
--push \
|
||||||
.
|
.
|
||||||
@@ -57,7 +56,6 @@ build_image() {
|
|||||||
-t "$full_version" \
|
-t "$full_version" \
|
||||||
-t "$image_name:latest" \
|
-t "$image_name:latest" \
|
||||||
--build-arg DATABASE_URL="postgresql://p@p:5432/p" \
|
--build-arg DATABASE_URL="postgresql://p@p:5432/p" \
|
||||||
--build-arg VITE_SELF_HOSTED="true" \
|
|
||||||
-f "apps/$app/Dockerfile" \
|
-f "apps/$app/Dockerfile" \
|
||||||
--push \
|
--push \
|
||||||
.
|
.
|
||||||
|
|||||||
60
sh/tag-self-hosting
Executable file
60
sh/tag-self-hosting
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Tags to manage
|
||||||
|
TAGS=("self-hosting")
|
||||||
|
|
||||||
|
# Get commit from argument or default to HEAD
|
||||||
|
COMMIT="${1:-HEAD}"
|
||||||
|
|
||||||
|
echo "🏷️ Managing tags: ${TAGS[@]}"
|
||||||
|
echo "📍 Target commit: $COMMIT"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Verify commit exists
|
||||||
|
if ! git rev-parse --verify "$COMMIT" >/dev/null 2>&1; then
|
||||||
|
echo "❌ Error: Invalid commit reference: $COMMIT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Delete local tags
|
||||||
|
echo "🗑️ Deleting local tags..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
if git tag -l "$tag" | grep -q "$tag"; then
|
||||||
|
git tag -d "$tag"
|
||||||
|
echo " ✓ Deleted local tag: $tag"
|
||||||
|
else
|
||||||
|
echo " - Tag $tag doesn't exist locally"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Delete remote tags
|
||||||
|
echo "🗑️ Deleting remote tags..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then
|
||||||
|
SKIP_HOOKS=1 git push origin ":refs/tags/$tag" 2>/dev/null
|
||||||
|
echo " ✓ Deleted remote tag: $tag"
|
||||||
|
else
|
||||||
|
echo " - Tag $tag doesn't exist on remote"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create new tags
|
||||||
|
echo "🏷️ Creating new tags on commit $COMMIT..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
git tag "$tag" "$COMMIT"
|
||||||
|
echo " ✓ Created tag: $tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Push tags
|
||||||
|
echo "🚀 Pushing tags to remote..."
|
||||||
|
SKIP_HOOKS=1 git push origin "${TAGS[@]}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Done! Tags updated successfully."
|
||||||
|
|
||||||
60
sh/tag-supporter
Executable file
60
sh/tag-supporter
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Tags to manage
|
||||||
|
TAGS=("api" "worker" "dashboard")
|
||||||
|
|
||||||
|
# Get commit from argument or default to HEAD
|
||||||
|
COMMIT="${1:-HEAD}"
|
||||||
|
|
||||||
|
echo "🏷️ Managing tags: ${TAGS[@]}"
|
||||||
|
echo "📍 Target commit: $COMMIT"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Verify commit exists
|
||||||
|
if ! git rev-parse --verify "$COMMIT" >/dev/null 2>&1; then
|
||||||
|
echo "❌ Error: Invalid commit reference: $COMMIT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Delete local tags
|
||||||
|
echo "🗑️ Deleting local tags..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
if git tag -l "$tag" | grep -q "$tag"; then
|
||||||
|
git tag -d "$tag"
|
||||||
|
echo " ✓ Deleted local tag: $tag"
|
||||||
|
else
|
||||||
|
echo " - Tag $tag doesn't exist locally"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Delete remote tags
|
||||||
|
echo "🗑️ Deleting remote tags..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
if git ls-remote --tags origin | grep -q "refs/tags/$tag"; then
|
||||||
|
SKIP_HOOKS=1 git push origin ":refs/tags/$tag" 2>/dev/null
|
||||||
|
echo " ✓ Deleted remote tag: $tag"
|
||||||
|
else
|
||||||
|
echo " - Tag $tag doesn't exist on remote"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create new tags
|
||||||
|
echo "🏷️ Creating new tags on commit $COMMIT..."
|
||||||
|
for tag in "${TAGS[@]}"; do
|
||||||
|
git tag "$tag" "$COMMIT"
|
||||||
|
echo " ✓ Created tag: $tag"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Push tags
|
||||||
|
echo "🚀 Pushing tags to remote..."
|
||||||
|
SKIP_HOOKS=1 git push origin "${TAGS[@]}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Done! Tags updated successfully."
|
||||||
|
|
||||||
Reference in New Issue
Block a user