33# Validates changelog, syncs version across files, creates tag, and pushes.
44#
55# Usage:
6- # ./scripts/release.sh 0.3.0
6+ # ./scripts/release.sh 0.3.0 # New release
7+ # ./scripts/release.sh 0.3.0 --force # Re-release (deletes existing tag)
78# ./scripts/release.sh 0.3.0 --dry-run # Preview without changes
89#
910# Prerequisites:
@@ -24,23 +25,33 @@ CHANGELOG="$PROJECT_DIR/CHANGELOG.md"
2425PACKAGE_JSON=" $PROJECT_DIR /package.json"
2526TAURI_CONF=" $PROJECT_DIR /src-tauri/tauri.conf.json"
2627
27- VERSION=" $1 "
28+ VERSION=" "
2829DRY_RUN=false
30+ FORCE=false
2931
30- if [ " $2 " = " --dry-run" ]; then
31- DRY_RUN=true
32- fi
32+ for arg in " $@ " ; do
33+ case " $arg " in
34+ --dry-run) DRY_RUN=true ;;
35+ --force) FORCE=true ;;
36+ -* ) echo -e " ${RED} Unknown flag: $arg ${NC} " ; exit 1 ;;
37+ * ) VERSION=" $arg " ;;
38+ esac
39+ done
3340
3441# ── Validate input ──
3542
3643if [ -z " $VERSION " ]; then
3744 echo -e " ${RED} Error: version required${NC} "
3845 echo " "
39- echo " Usage: ./scripts/release.sh <version> [--dry-run]"
40- echo " Example: ./scripts/release.sh 0.4.0"
46+ echo " Usage: ./scripts/release.sh <version> [--dry-run] [--force]"
47+ echo " "
48+ echo " Examples:"
49+ echo " ./scripts/release.sh 0.4.0 # New release"
50+ echo " ./scripts/release.sh 0.3.0 --force # Re-release existing version"
51+ echo " ./scripts/release.sh 0.4.0 --dry-run # Preview"
4152 echo " "
4253 echo " Before running, document the release in CHANGELOG.md:"
43- echo " ## [$VERSION ] - $( date +%Y-%m-%d) "
54+ echo " ## [x.x.x ] - $( date +%Y-%m-%d) "
4455 exit 1
4556fi
4657
@@ -49,6 +60,9 @@ VERSION="${VERSION#v}"
4960
5061echo " "
5162echo " === SQLMap UI Release v$VERSION ==="
63+ if [ " $FORCE " = true ]; then
64+ echo -e " ${YELLOW} (force mode: will replace existing tag)${NC} "
65+ fi
5266echo " "
5367
5468# ── Check clean working tree ──
@@ -85,7 +99,7 @@ if [ -z "$CHANGELOG_ENTRY" ]; then
8599fi
86100
87101# Validate it has a date
88- if ! echo " $CHANGELOG_ENTRY " | grep -qE " \d {4}-\d {2}-\d {2}" ; then
102+ if ! echo " $CHANGELOG_ENTRY " | grep -qE " [0-9] {4}-[0-9] {2}-[0-9] {2}" ; then
89103 echo -e " ${RED} Error: version $VERSION in CHANGELOG.md has no date${NC} "
90104 echo " Expected format: ## [$VERSION ] - YYYY-MM-DD"
91105 exit 1
99113
100114echo -e " ${GREEN} CHANGELOG.md:${NC} $CHANGELOG_ENTRY "
101115
102- # ── Validate tag doesn't already exist ──
116+ # ── Detect remote ──
103117
104- if git -C " $PROJECT_DIR " tag -l " v$VERSION " | grep -q " v$VERSION " ; then
105- echo -e " ${RED} Error: tag v$VERSION already exists${NC} "
118+ REMOTE=$( git -C " $PROJECT_DIR " remote | head -1)
119+ if [ -z " $REMOTE " ]; then
120+ echo -e " ${RED} Error: no git remote configured${NC} "
106121 exit 1
107122fi
123+ BRANCH=$( git -C " $PROJECT_DIR " branch --show-current)
124+
125+ # ── Check if tag already exists ──
126+
127+ TAG_EXISTS_LOCAL=$( git -C " $PROJECT_DIR " tag -l " v$VERSION " )
128+ TAG_EXISTS_REMOTE=$( git -C " $PROJECT_DIR " ls-remote --tags " $REMOTE " " v$VERSION " 2> /dev/null | head -1 || true)
129+
130+ if [ -n " $TAG_EXISTS_LOCAL " ] || [ -n " $TAG_EXISTS_REMOTE " ]; then
131+ if [ " $FORCE " = false ]; then
132+ echo -e " ${RED} Error: tag v$VERSION already exists${NC} "
133+ echo " Use --force to re-release: ./scripts/release.sh $VERSION --force"
134+ exit 1
135+ fi
136+ echo -e " ${YELLOW} Tag v$VERSION exists, will be replaced${NC} "
137+ fi
108138
109139# ── Show what will change ──
110140
111141CURRENT_PKG=$( grep ' "version"' " $PACKAGE_JSON " | head -1 | sed ' s/.*"version": "\(.*\)".*/\1/' )
112142CURRENT_TAURI=$( grep ' "version"' " $TAURI_CONF " | head -1 | sed ' s/.*"version": "\(.*\)".*/\1/' )
113143
114144echo " "
115- echo " Version updates:"
116- echo " package.json: $CURRENT_PKG -> $VERSION "
117- echo " tauri.conf.json: $CURRENT_TAURI -> $VERSION "
118- echo " git tag: v$VERSION "
145+ echo " Plan:"
146+ if [ " $CURRENT_PKG " != " $VERSION " ] || [ " $CURRENT_TAURI " != " $VERSION " ]; then
147+ echo " 1. Update package.json: $CURRENT_PKG -> $VERSION "
148+ echo " Update tauri.conf.json: $CURRENT_TAURI -> $VERSION "
149+ echo " Commit version bump"
150+ else
151+ echo " 1. Version already at $VERSION (no commit needed)"
152+ fi
153+ if [ -n " $TAG_EXISTS_LOCAL " ] || [ -n " $TAG_EXISTS_REMOTE " ]; then
154+ echo " 2. Delete existing tag v$VERSION (local + remote)"
155+ echo " 3. Create new tag v$VERSION "
156+ else
157+ echo " 2. Create tag v$VERSION "
158+ fi
159+ echo " *. Push $BRANCH + tags to $REMOTE "
160+ echo " -> GitHub Actions builds installers and creates release"
119161echo " "
120162
121163if [ " $DRY_RUN " = true ]; then
134176
135177# ── Update versions ──
136178
137- # package.json
138- sed -i.bak " s/\" version\" : \" $CURRENT_PKG \" /\" version\" : \" $VERSION \" /" " $PACKAGE_JSON "
139- rm -f " $PACKAGE_JSON .bak"
140-
141- # tauri.conf.json
142- sed -i.bak " s/\" version\" : \" $CURRENT_TAURI \" /\" version\" : \" $VERSION \" /" " $TAURI_CONF "
143- rm -f " $TAURI_CONF .bak"
144-
145- echo -e " ${GREEN} Updated versions in package.json and tauri.conf.json${NC} "
146-
147- # ── Detect remote name ──
179+ if [ " $CURRENT_PKG " != " $VERSION " ]; then
180+ sed -i.bak " s/\" version\" : \" $CURRENT_PKG \" /\" version\" : \" $VERSION \" /" " $PACKAGE_JSON "
181+ rm -f " $PACKAGE_JSON .bak"
182+ fi
148183
149- REMOTE=$( git -C " $PROJECT_DIR " remote | head -1)
150- if [ -z " $REMOTE " ]; then
151- echo -e " ${RED} Error: no git remote configured${NC} "
152- exit 1
184+ if [ " $CURRENT_TAURI " != " $VERSION " ]; then
185+ sed -i.bak " s/\" version\" : \" $CURRENT_TAURI \" /\" version\" : \" $VERSION \" /" " $TAURI_CONF "
186+ rm -f " $TAURI_CONF .bak"
153187fi
154- BRANCH=$( git -C " $PROJECT_DIR " branch --show-current)
155- echo " Remote: $REMOTE ($BRANCH )"
156188
157189# ── Commit version bump (only if there are changes) ──
158190
@@ -166,6 +198,19 @@ else
166198 echo -e " ${GREEN} Committed version bump${NC} "
167199fi
168200
201+ # ── Delete existing tag if force ──
202+
203+ if [ " $FORCE " = true ]; then
204+ if [ -n " $TAG_EXISTS_LOCAL " ]; then
205+ git tag -d " v$VERSION " 2> /dev/null || true
206+ echo -e " ${YELLOW} Deleted local tag v$VERSION ${NC} "
207+ fi
208+ if [ -n " $TAG_EXISTS_REMOTE " ]; then
209+ git push " $REMOTE " --delete " v$VERSION " 2> /dev/null || true
210+ echo -e " ${YELLOW} Deleted remote tag v$VERSION ${NC} "
211+ fi
212+ fi
213+
169214# ── Create tag ──
170215
171216git tag -a " v$VERSION " -m " Release v$VERSION "
0 commit comments