@@ -4,8 +4,10 @@ set -euo pipefail
44# # upgrade-packs.sh
55# # Upgrade CodeQL pack dependencies for packs in the codeql-sap-js repository.
66# #
7- # # This script upgrades lock files for both source and test packs, installing
8- # # the latest compatible version of each dependency (ignoring existing lock files).
7+ # # This script resolves the latest compatible versions of external CodeQL pack
8+ # # dependencies (e.g., codeql/javascript-all), pins qlpack.yml dependency
9+ # # references to those exact versions, and then upgrades lock files for both
10+ # # source and test packs.
911# #
1012# # Usage:
1113# # ./scripts/upgrade-packs.sh
7577
7678cd " ${REPO_ROOT} "
7779
80+ # # External CodeQL pack dependencies whose versions should be pinned explicitly.
81+ # # Each entry is a pack name used under the 'dependencies:' key in qlpack.yml files.
82+ # # External CodeQL pack dependencies whose versions should be pinned explicitly.
83+ # # Each entry is a pack name referenced under 'dependencies:' or 'extensionTargets:'
84+ # # in qlpack.yml files.
85+ EXTERNAL_PACKS=(
86+ " codeql/javascript-all"
87+ " codeql/javascript-queries"
88+ )
89+
90+ # # Resolve the latest compatible version of an external pack using the CodeQL CLI.
91+ # # Uses 'codeql pack download --format=json' which resolves and caches the latest
92+ # # version compatible with the current CLI.
93+ resolve_pack_version () {
94+ local pack_name=" $1 "
95+ local version
96+ version=$( codeql pack download --format=json " ${pack_name} " 2> /dev/null \
97+ | python3 -c " import sys,json; packs=json.load(sys.stdin)['packs']; print(packs[0]['version'])" 2> /dev/null)
98+ if [[ -z " ${version} " ]]; then
99+ echo " ERROR: Failed to resolve version for ${pack_name} " >&2
100+ return 1
101+ fi
102+ echo " ${version} "
103+ }
104+
105+ # # Pin external pack dependency versions in all qlpack.yml files.
106+ # # Updates both 'dependencies:' and 'extensionTargets:' entries to reference
107+ # # the exact resolved version.
108+ # # Handles both unquoted and quoted key formats:
109+ # # pack_name: "^X.Y.Z" or pack_name: "X.Y.Z" or "pack_name": "X.Y.Z"
110+ pin_external_dependency_versions () {
111+ echo " Resolving latest compatible versions of external pack dependencies..."
112+
113+ # Build an associative array of pack_name -> resolved_version
114+ declare -A resolved_versions
115+ for pack_name in " ${EXTERNAL_PACKS[@]} " ; do
116+ local version
117+ version=$( resolve_pack_version " ${pack_name} " )
118+ resolved_versions[" ${pack_name} " ]=" ${version} "
119+ echo " ${pack_name} -> ${version} "
120+ done
121+
122+ echo " "
123+ echo " Pinning external dependency versions in qlpack.yml files..."
124+
125+ # Find all qlpack.yml files under javascript/ (excluding .codeql pack cache directories)
126+ find " ${REPO_ROOT} /javascript" -name " qlpack.yml" -not -path " */.codeql/*" -type f | sort | while read -r qlpack_file; do
127+ local rel_path=" ${qlpack_file# ${REPO_ROOT} / } "
128+ local changed=false
129+
130+ for pack_name in " ${EXTERNAL_PACKS[@]} " ; do
131+ local new_version=" ${resolved_versions[${pack_name}]} "
132+
133+ # Update any reference to this pack (under dependencies: or extensionTargets:)
134+ # Update quoted versions with optional range prefix (^, >, >=): "^X.Y.Z", ">X.Y.Z", "X.Y.Z"
135+ if grep -q " ${pack_name} " " ${qlpack_file} " ; then
136+ sed -i.bak -E " s|(${pack_name} \" ?:[[:space:]]*\" )[>^>=]*[0-9]+\.[0-9]+\.[0-9]+\" |\1${new_version} \" |g" " ${qlpack_file} "
137+ rm -f " ${qlpack_file} .bak"
138+ # Also handle the quoted-key form: "pack_name": "X.Y.Z"
139+ sed -i.bak -E " s|(\" ${pack_name} \" :[[:space:]]*\" )[>^>=]*[0-9]+\.[0-9]+\.[0-9]+\" |\1${new_version} \" |g" " ${qlpack_file} "
140+ rm -f " ${qlpack_file} .bak"
141+ changed=true
142+ fi
143+ done
144+
145+ if [[ " ${changed} " == true ]]; then
146+ echo " ✅ ${rel_path} "
147+ fi
148+ done
149+
150+ echo " "
151+
152+ # Remove existing lock files to force fresh dependency resolution
153+ echo " Removing existing codeql-pack.lock.yml files..."
154+ find " ${REPO_ROOT} /javascript" -name " codeql-pack.lock.yml" -not -path " */.codeql/*" -type f -exec rm -f {} \;
155+ echo " "
156+ }
157+
78158# # Upgrade a single pack given its qlpack.yml directory
79159upgrade_pack () {
80160 local pack_dir=" $1 "
@@ -92,7 +172,8 @@ upgrade_framework() {
92172 echo " Upgrading packs for: ${framework_path} "
93173
94174 # Find all qlpack.yml files under this framework and upgrade their packs
95- find " ${REPO_ROOT} /${framework_path} " -name " qlpack.yml" -type f | sort | while read -r qlpack_file; do
175+ # Excludes .codeql/ pack cache directories which contain previously published packs
176+ find " ${REPO_ROOT} /${framework_path} " -name " qlpack.yml" -not -path " */.codeql/*" -type f | sort | while read -r qlpack_file; do
96177 local pack_dir
97178 pack_dir=$( dirname " ${qlpack_file} " )
98179 # Use relative path for cleaner output
@@ -102,6 +183,7 @@ upgrade_framework() {
102183}
103184
104185if [[ -n " ${FRAMEWORK} " ]]; then
186+ pin_external_dependency_versions
105187 case " ${FRAMEWORK} " in
106188 heuristic-models)
107189 upgrade_framework " javascript/heuristic-models"
@@ -114,6 +196,7 @@ if [[ -n "${FRAMEWORK}" ]]; then
114196 ;;
115197 esac
116198else
199+ pin_external_dependency_versions
117200 echo " Upgrading packs for all frameworks..."
118201 upgrade_framework " javascript/frameworks/cap"
119202 upgrade_framework " javascript/frameworks/ui5"
0 commit comments