summaryrefslogtreecommitdiff
path: root/scripts/prepare_release.sh
blob: 02e3df8398e0107cd4ff6bb3fbd6face9cc0cd31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env bash
# prepare_release.sh
# Prepares a ThreadX release by updating version constants and port version strings.
#
# Usage:   prepare_release.sh <version>
# Example: prepare_release.sh 6.5.1.202602
# Hotfix:  prepare_release.sh 6.5.1.202602a
#
# This script:
#   1. Creates branch release-<version>-preparation from dev
#   2. Updates version constants in common/inc/tx_api.h
#      (commit: "Updated version number constants")
#   3. Updates port version strings in all tx_port.h files
#      (commit: "Updated port version strings")
#
# Copyright (C) 2026 Eclipse ThreadX contributors
# SPDX-License-Identifier: MIT
# Portions of this file were generated with AI assistance.

set -eu

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

API_HEADER="${REPO_ROOT}/common/inc/tx_api.h"
PORT_HEADER_NAME="tx_port.h"
PORT_DIRS="ports ports_smp ports_arch ports_module"

# --------------------------------------------------------------------------
# Argument validation
# --------------------------------------------------------------------------
if [ "$#" -ne 1 ]; then
    printf "Usage: %s <version>\n" "$(basename "$0")" >&2
    printf "Example: %s 6.5.1.202602\n" "$(basename "$0")" >&2
    exit 1
fi

VERSION="$1"

if ! printf "%s" "${VERSION}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[a-z]?$'; then
    printf "Error: Invalid version format '%s'.\n" "${VERSION}" >&2
    printf "Expected: MAJOR.MINOR.PATCH.BUILD[hotfix_letter]\n" >&2
    exit 1
fi

# --------------------------------------------------------------------------
# Parse version components
# --------------------------------------------------------------------------
MAJOR=$(printf "%s" "${VERSION}" | cut -d. -f1)
MINOR=$(printf "%s" "${VERSION}" | cut -d. -f2)
PATCH=$(printf "%s" "${VERSION}" | cut -d. -f3)
BUILD_AND_HOTFIX=$(printf "%s" "${VERSION}" | cut -d. -f4)
BUILD=$(printf "%s" "${BUILD_AND_HOTFIX}" | sed -E 's/[a-z]+$//')
HOTFIX=$(printf "%s" "${BUILD_AND_HOTFIX}" | sed -E 's/^[0-9]+//')

if [ -z "${HOTFIX}" ]; then
    HOTFIX_DEFINE="' '"
else
    HOTFIX_DEFINE="'${HOTFIX}'"
fi

# --------------------------------------------------------------------------
# Read and display current version
# --------------------------------------------------------------------------
CURR_MAJOR=$(grep -E "^#define THREADX_MAJOR_VERSION" "${API_HEADER}" | awk '{print $NF}')
CURR_MINOR=$(grep -E "^#define THREADX_MINOR_VERSION" "${API_HEADER}" | awk '{print $NF}')
CURR_PATCH=$(grep -E "^#define THREADX_PATCH_VERSION" "${API_HEADER}" | awk '{print $NF}')
CURR_BUILD=$(grep -E "^#define THREADX_BUILD_VERSION" "${API_HEADER}" | awk '{print $NF}')
CURR_HOTFIX=$(grep -E "^#define THREADX_HOTFIX_VERSION" "${API_HEADER}" | \
              sed -E "s/.*'([^']*)'.*/\1/" | tr -d ' ')

if [ -z "${CURR_HOTFIX}" ]; then
    CURR_VER="${CURR_MAJOR}.${CURR_MINOR}.${CURR_PATCH}.${CURR_BUILD}"
else
    CURR_VER="${CURR_MAJOR}.${CURR_MINOR}.${CURR_PATCH}.${CURR_BUILD}${CURR_HOTFIX}"
fi

printf "\nThreadX release preparation\n"
printf "  Repository      : %s\n" "${REPO_ROOT}"
printf "  Current version : %s\n" "${CURR_VER}"
printf "  Target version  : %s\n\n" "${VERSION}"

# --------------------------------------------------------------------------
# Port consistency checks
# --------------------------------------------------------------------------
# Run before anything is branched or rewritten, so a release is never cut on
# top of ports that have drifted from ports_arch or headers that cannot
# compile. Set SKIP_PORT_CHECKS=1 to proceed anyway.
if [ "${SKIP_PORT_CHECKS:-0}" = "1" ]; then
    printf "Skipping the port consistency checks (SKIP_PORT_CHECKS=1).\n\n"
elif ! "${SCRIPT_DIR}/check_ports.sh"; then
    printf "\nRelease preparation stopped: the port consistency checks failed.\n"
    printf "Fix the problems above, or set SKIP_PORT_CHECKS=1 to proceed anyway.\n"
    exit 1
fi
printf "Proceed with update? [y/N] "
read -r CONFIRM
case "${CONFIRM}" in
    y|Y) ;;
    *)
        printf "Aborted.\n"
        exit 0
        ;;
esac

# --------------------------------------------------------------------------
# Pre-flight checks
# --------------------------------------------------------------------------
if ! git -C "${REPO_ROOT}" diff --quiet HEAD 2>/dev/null; then
    printf "Error: Working tree has uncommitted changes. Commit or stash first.\n" >&2
    exit 1
fi

# --------------------------------------------------------------------------
# Create feature branch from dev
# --------------------------------------------------------------------------
BRANCH_NAME="release-${VERSION}-preparation"
printf "\nChecking out dev and pulling latest changes...\n"
git -C "${REPO_ROOT}" checkout dev
git -C "${REPO_ROOT}" pull origin dev
printf "Creating branch '%s'...\n" "${BRANCH_NAME}"
git -C "${REPO_ROOT}" checkout -b "${BRANCH_NAME}"

# --------------------------------------------------------------------------
# Update version constants
# --------------------------------------------------------------------------
printf "\nUpdating version constants in %s...\n" "${API_HEADER}"

sed -i -E "s|(#define THREADX_MAJOR_VERSION[[:space:]]+)[0-9]+|\1${MAJOR}|" "${API_HEADER}"
sed -i -E "s|(#define THREADX_MINOR_VERSION[[:space:]]+)[0-9]+|\1${MINOR}|" "${API_HEADER}"
sed -i -E "s|(#define THREADX_PATCH_VERSION[[:space:]]+)[0-9]+|\1${PATCH}|" "${API_HEADER}"
sed -i -E "s|(#define THREADX_BUILD_VERSION[[:space:]]+)[0-9]+|\1${BUILD}|" "${API_HEADER}"
sed -i -E "s|(#define THREADX_HOTFIX_VERSION[[:space:]]+)'[^']*'|\1${HOTFIX_DEFINE}|" "${API_HEADER}"

git -C "${REPO_ROOT}" add "${API_HEADER}"
git -C "${REPO_ROOT}" commit -F - <<'COMMIT_EOF'
Updated version number constants
COMMIT_EOF

printf "Committed version constant updates.\n"

# --------------------------------------------------------------------------
# Update port version strings
# --------------------------------------------------------------------------
printf "\nUpdating port version strings...\n"

PORT_FILES=""
for dir in ${PORT_DIRS}; do
    if [ -d "${REPO_ROOT}/${dir}" ]; then
        found=$(find "${REPO_ROOT}/${dir}" -name "${PORT_HEADER_NAME}" 2>/dev/null | sort)
        if [ -n "${found}" ]; then
            PORT_FILES="${PORT_FILES}${found}
"
        fi
    fi
done
PORT_FILES=$(printf "%s" "${PORT_FILES}" | grep -v '^[[:space:]]*$' || true)

if [ -z "${PORT_FILES}" ]; then
    printf "Warning: No port header files found. Skipping port version string commit.\n"
else
    # A port advertises its release in the string the library reports at run time.
    # The pattern accepts three or four dotted numbers and tolerates a stray
    # letter before the first one, so a port that writes its version slightly
    # differently is still reached.
    VERSION_RE='Version[[:space:]]+[A-Za-z]?[0-9]+(\.[0-9]+)+[a-z]*'
    while IFS= read -r port_file; do
        if [ -n "${port_file}" ] && grep -qE "${VERSION_RE}" "${port_file}" 2>/dev/null; then
            sed -i -E "s/${VERSION_RE}/Version ${VERSION}/g" "${port_file}"
            printf "  Updated: %s\n" "${port_file#${REPO_ROOT}/}"
        fi
    done <<EOF
${PORT_FILES}
EOF

    # Every port header that names a release must now name this one.  A port
    # whose string is shaped in some other way is not rewritten above, and
    # without this check the pass reports success while leaving that port
    # advertising the previous release for the life of the version.
    STALE=""
    while IFS= read -r port_file; do
        [ -n "${port_file}" ] || continue
        advertised=$(grep -hoE '"[^"]*[0-9]+\.[0-9]+\.[0-9]+[^"]*"' "${port_file}" 2>/dev/null || true)
        [ -n "${advertised}" ] || continue
        if ! printf "%s" "${advertised}" | grep -qF "${VERSION}"; then
            STALE="${STALE}  ${port_file#${REPO_ROOT}/}
"
        fi
    done <<EOF
${PORT_FILES}
EOF
    if [ -n "${STALE}" ]; then
        printf "\nError: these port headers still advertise another release:\n%s" "${STALE}" >&2
        printf "Correct them so the substitution above reaches them, then re-run.\n" >&2
        exit 1
    fi

    git -C "${REPO_ROOT}" add -u
    if git -C "${REPO_ROOT}" diff --cached --quiet; then
        printf "No port version string changes staged. Skipping commit.\n"
    else
        git -C "${REPO_ROOT}" commit -F - <<'COMMIT_EOF'
Updated port version strings
COMMIT_EOF
        printf "Committed port version string updates.\n"
    fi
fi

printf "\nRelease preparation complete.\n"
printf "Branch '%s' is ready for review.\n" "${BRANCH_NAME}"