1+ #! /bin/bash
2+
3+ # Script: deprecate-updated-packages.sh
4+ # Description:
5+ # This script detects package version updates in the latest commit, deprecates the updated versions,
6+ # and maintains the 'latest' tag to point to the previous stable version. It only processes packages
7+ # where the version number has actually changed.
8+ #
9+ # For each updated package, it will:
10+ # 1. Verify if the version number has changed from the previous commit
11+ # 2. If version changed, deprecate the current version
12+ # 3. Update the 'latest' tag to point to the previous stable version
13+ #
14+ # Usage:
15+ # ./deprecate-updated-packages.sh [options]
16+ #
17+ # Options:
18+ # --dry-run Show what would be deprecated without actually executing npm commands
19+ # --token=TOKEN Use the provided npm authentication token
20+ # --registry=REGISTRY Specify the npm registry (default: https://registry.npmjs.org/)
21+ # --help Show this help message
22+ #
23+ # Examples:
24+ # # Dry run with default npm registry
25+ # ./deprecate-updated-packages.sh --dry-run
26+ #
27+ # # Execute with custom registry and token
28+ # ./deprecate-updated-packages.sh --token=your-token --registry=https://your-registry.com/
29+ #
30+ # # Using environment variables
31+ # NPM_TOKEN=your-token NPM_REGISTRY=https://your-registry.com/ ./deprecate-updated-packages.sh
32+
33+ # Initialize variables
34+ DRY_RUN=false
35+ NPM_TOKEN=" "
36+ NPM_REGISTRY=" https://registry.npmjs.org/"
37+ NPM_WEBSITE=" https://www.npmjs.com"
38+
39+ # Statistics
40+ TOTAL_PACKAGES=0
41+ SUCCESS_COUNT=0
42+ SUCCESS_PACKAGES=()
43+ FAILED_PACKAGES=()
44+
45+ # Show help if requested
46+ if [[ " $* " =~ " --help " ]] || [[ " $* " =~ " -h " ]]; then
47+ grep ' ^# ' " $0 " | sed ' s/^# //g'
48+ exit 0
49+ fi
50+
51+ # Parse command line arguments
52+ for arg in " $@ " ; do
53+ case $arg in
54+ --dry-run)
55+ DRY_RUN=true
56+ shift # past argument
57+ ;;
58+ --token=* )
59+ NPM_TOKEN=" ${arg#* =} "
60+ shift # past argument
61+ ;;
62+ --registry=* )
63+ NPM_REGISTRY=" ${arg#* =} "
64+ # Ensure registry URL ends with a slash
65+ [[ " $NPM_REGISTRY " != * / ]] && NPM_REGISTRY=" $NPM_REGISTRY /"
66+ shift # past argument
67+ ;;
68+ * )
69+ # Unknown option
70+ echo " Unknown option: $arg "
71+ exit 1
72+ ;;
73+ esac
74+ done
75+
76+ # Set npm registry
77+ if [ -n " $NPM_TOKEN " ]; then
78+ echo " 🔑 Using provided npm token"
79+ export NPM_TOKEN=" $NPM_TOKEN "
80+ fi
81+ echo " 🌐 Using npm registry: $NPM_REGISTRY "
82+
83+ echo " 🔍 Checking for updated package.json files in the latest commit..."
84+
85+ # Get modified files in the latest commit and filter for packages/*/package.json
86+ UPDATED_PACKAGES=$( git diff --name-only HEAD^ HEAD | grep ' ^packages/.*/package\.json$' )
87+
88+ if [ -z " $UPDATED_PACKAGES " ]; then
89+ echo " ℹ️ No updated packages/*/package.json files found in the latest commit"
90+ exit 0
91+ fi
92+
93+ echo " 📦 Found the following updated package.json files:"
94+ echo " $UPDATED_PACKAGES "
95+ echo " "
96+
97+ # Process each updated package.json file
98+ for PACKAGE_JSON in $UPDATED_PACKAGES ; do
99+ # Get current package name and version
100+ PACKAGE_NAME=$( jq -r ' .name' " $PACKAGE_JSON " )
101+ CURRENT_VERSION=$( jq -r ' .version' " $PACKAGE_JSON " )
102+
103+ # Get the previous version from the parent commit
104+ PREVIOUS_VERSION=$( git show HEAD^:" $PACKAGE_JSON " | jq -r ' .version' 2> /dev/null || echo " " )
105+
106+ # Skip if we couldn't get the previous version
107+ if [ -z " $PREVIOUS_VERSION " ] || [ " $PREVIOUS_VERSION " = " null" ]; then
108+ echo " ⚠️ Could not determine previous version for $PACKAGE_JSON , skipping..."
109+ continue
110+ fi
111+
112+ # Skip if version hasn't changed
113+ if [ " $CURRENT_VERSION " = " $PREVIOUS_VERSION " ]; then
114+ echo " ℹ️ Version not changed for $PACKAGE_NAME (still $CURRENT_VERSION ), skipping..."
115+ continue
116+ fi
117+
118+ # Increment total packages counter
119+ (( TOTAL_PACKAGES++ ))
120+
121+ # Generate package URLs (npm website format)
122+ PACKAGE_URL=" ${NPM_WEBSITE} /package/${PACKAGE_NAME} /v/${CURRENT_VERSION} "
123+ PREVIOUS_PACKAGE_URL=" ${NPM_WEBSITE} /package/${PACKAGE_NAME} /v/${PREVIOUS_VERSION} "
124+
125+ # For scoped packages, need to handle the @ symbol in the URL
126+ if [[ $PACKAGE_NAME == @* ]]; then
127+ PACKAGE_URL=" ${NPM_WEBSITE} /package/${PACKAGE_NAME/@/% 40} /v/${CURRENT_VERSION} "
128+ PREVIOUS_PACKAGE_URL=" ${NPM_WEBSITE} /package/${PACKAGE_NAME/@/% 40} /v/${PREVIOUS_VERSION} "
129+ fi
130+
131+ if [ " $PACKAGE_NAME " = " null" ] || [ " $CURRENT_VERSION " = " null" ]; then
132+ echo " ⚠️ Skipping invalid package.json: $PACKAGE_JSON "
133+ continue
134+ fi
135+
136+ DEPRECATION_MESSAGE=" This version has been deprecated. Please upgrade to the latest version."
137+
138+ if [ " $DRY_RUN " = true ]; then
139+ echo " 🔄 [DRY RUN] Would deprecate package: $PACKAGE_NAME @$CURRENT_VERSION "
140+ echo " Previous version (latest tag would point to): $PACKAGE_NAME @$PREVIOUS_VERSION "
141+ echo " Command: npm deprecate $PACKAGE_NAME @$CURRENT_VERSION \" $DEPRECATION_MESSAGE \" "
142+ echo " Package URL: $PACKAGE_URL "
143+ echo " Previous version URL: $PREVIOUS_PACKAGE_URL "
144+ echo " ✅ [DRY RUN] Success (simulated):"
145+ echo " - Deprecated: $PACKAGE_NAME @$CURRENT_VERSION "
146+ echo " - Latest tag would point to: $PACKAGE_NAME @$PREVIOUS_VERSION "
147+ else
148+ echo " 🔄 Processing package: $PACKAGE_NAME "
149+ echo " - Current version to deprecate: $CURRENT_VERSION "
150+ echo " - Previous version (will be tagged as latest): $PREVIOUS_VERSION "
151+ echo " Executing: npm deprecate $PACKAGE_NAME @$CURRENT_VERSION \" $DEPRECATION_MESSAGE \" "
152+ echo " Package URL: $PACKAGE_URL "
153+ echo " Previous version URL: $PREVIOUS_PACKAGE_URL "
154+
155+ # Execute npm deprecate command with registry and token if provided
156+ if [ -n " $NPM_TOKEN " ]; then
157+ npm --registry=" $NPM_REGISTRY " --//${NPM_REGISTRY#*// } :_authToken=" $NPM_TOKEN " deprecate " $PACKAGE_NAME @$CURRENT_VERSION " " $DEPRECATION_MESSAGE "
158+ else
159+ npm --registry=" $NPM_REGISTRY " deprecate " $PACKAGE_NAME @$CURRENT_VERSION " " $DEPRECATION_MESSAGE "
160+ fi
161+
162+ if [ $? -eq 0 ]; then
163+ echo " ✅ Successfully deprecated: $PACKAGE_NAME @$CURRENT_VERSION "
164+ echo " Package URL: $PACKAGE_URL "
165+
166+ # Now, update the 'latest' tag to point to the previous version
167+ echo " 🔄 Updating 'latest' tag to point to previous version: $PACKAGE_NAME @$PREVIOUS_VERSION "
168+ echo " This will make version $PREVIOUS_VERSION the new 'latest' version"
169+ if [ -n " $NPM_TOKEN " ]; then
170+ npm --registry=" $NPM_REGISTRY " --//${NPM_REGISTRY#*// } :_authToken=" $NPM_TOKEN " dist-tag add " $PACKAGE_NAME @$PREVIOUS_VERSION " latest
171+ else
172+ npm --registry=" $NPM_REGISTRY " dist-tag add " $PACKAGE_NAME @$PREVIOUS_VERSION " latest
173+ fi
174+
175+ if [ $? -eq 0 ]; then
176+ echo " ✅ Successfully updated 'latest' tag to point to $PACKAGE_NAME @$PREVIOUS_VERSION "
177+ echo " Previous version URL: $PREVIOUS_PACKAGE_URL "
178+ (( SUCCESS_COUNT++ ))
179+ SUCCESS_PACKAGES+=(" $PACKAGE_NAME @$CURRENT_VERSION (deprecated), latest -> $PREVIOUS_VERSION " )
180+ else
181+ echo " ❌ Failed to update 'latest' tag for $PACKAGE_NAME "
182+ FAILED_PACKAGES+=(" $PACKAGE_NAME @$CURRENT_VERSION (deprecated, but failed to update latest tag)" )
183+ fi
184+ else
185+ echo " ❌ Failed to deprecate: $PACKAGE_NAME @$CURRENT_VERSION "
186+ echo " Package URL: $PACKAGE_URL "
187+ FAILED_PACKAGES+=(" $PACKAGE_NAME @$CURRENT_VERSION (failed to deprecate)" )
188+ fi
189+ fi
190+ echo " "
191+ done
192+
193+ if [ " $DRY_RUN " = true ]; then
194+ echo " ✨ Dry run completed. No packages were actually deprecated."
195+ echo " 📊 Would have processed $TOTAL_PACKAGES packages."
196+ else
197+ echo " 📊 Deprecation Summary:"
198+ echo " ✅ Successfully deprecated: $SUCCESS_COUNT "
199+ echo " ❌ Failed to deprecate: ${# FAILED_PACKAGES[@]} "
200+ echo " 📦 Total packages processed: $TOTAL_PACKAGES "
201+
202+ if [ $SUCCESS_COUNT -gt 0 ]; then
203+ echo -e " \n✅ Successfully deprecated packages:"
204+ for pkg in " ${SUCCESS_PACKAGES[@]} " ; do
205+ # Extract package name and version
206+ pkg_name=" ${pkg%@* } "
207+ pkg_version=" ${pkg#*@ } "
208+ # Encode package name for URL (only @ and / need to be encoded)
209+ encoded_pkg=$( echo " $pkg_name " | sed ' s/@/%40/g' | sed ' s/\//%2F/g' )
210+ echo " - $pkg (${NPM_WEBSITE} /package/${encoded_pkg} /v/${pkg_version} )"
211+ done
212+ fi
213+
214+ if [ ${# FAILED_PACKAGES[@]} -gt 0 ]; then
215+ echo -e " \n❌ Failed packages:"
216+ for pkg in " ${FAILED_PACKAGES[@]} " ; do
217+ # Extract package name and version
218+ pkg_name=" ${pkg%@* } "
219+ pkg_version=" ${pkg#*@ } "
220+ # Encode package name for URL (only @ and / need to be encoded)
221+ encoded_pkg=$( echo " $pkg_name " | sed ' s/@/%40/g' | sed ' s/\//%2F/g' )
222+ echo " - $pkg (${NPM_WEBSITE} /package/${encoded_pkg} /v/${pkg_version} )"
223+ done
224+ fi
225+
226+ if [ $SUCCESS_COUNT -eq $TOTAL_PACKAGES ]; then
227+ echo " \n✨ All $TOTAL_PACKAGES packages were processed successfully!"
228+ else
229+ echo " \n⚠️ Some packages failed to deprecate. See above for details."
230+ fi
231+ fi
0 commit comments