Skip to content

Commit 5a605d2

Browse files
authored
ci(versioning): crates-to-package.sh refactor (#1875)
# What does this PR do? Refactor to simplify `crates-to-package.sh`script: - No more awk parsing: the script now runs cargo metadata --no-deps at two refs (base/head) and compares package.version. - Uses git worktree (like scripts/major-bumps-level.sh) to run cargo metadata as of each ref. - Excludes are no longer hardcoded: a crate is included only if it’s a workspace member and publishable per metadata:
1 parent 1701392 commit 5a605d2

File tree

2 files changed

+81
-92
lines changed

2 files changed

+81
-92
lines changed

scripts/crates-to-package.sh

Lines changed: 79 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,112 +2,99 @@
22
# Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
33
# SPDX-License-Identifier: Apache-2.0
44
#
5-
# Compares every workspace package's effective [package] version between GIT_VERSION_BASE
6-
# and GIT_VERSION_HEAD. Prints package names suitable for `cargo package -p` when the version
7-
# changed — not when only dependency versions changed.
8-
# Uses git for both sides so results match the refs, not uncommitted working tree edits.
5+
# Compares workspace crate versions between two git refs by running `cargo metadata` at each ref.
6+
# Prints crate names suitable for `cargo package -p` when the crate's *own* package version changed.
97
#
10-
# CI should set GIT_VERSION_BASE / GIT_VERSION_HEAD to the commits being compared (e.g. PR base
11-
# and head). Defaults below are for local use; comparing to origin/main vs HEAD is not the same
12-
# as "what this PR changed" once main has moved.
8+
# Important: this intentionally ignores dependency version bumps unless they also changed the crate
9+
# version. (Cargo metadata reports package versions, not dependency requirements.)
10+
#
11+
# Excludes are determined from crate metadata: crates marked `publish = false` are excluded.
12+
# (Crates with publish unset or publish = [...] are considered publishable.)
13+
#
14+
# Important: this script is used by libddprof-build gitlab pipeline
1315

1416
set -euo pipefail
1517

1618
GIT_VERSION_BASE="${GIT_VERSION_BASE:-origin/main}"
1719
GIT_VERSION_HEAD="${GIT_VERSION_HEAD:-HEAD}"
1820

19-
# [workspace.package].version from workspace root Cargo.toml (stdin).
20-
workspace_package_version() {
21-
awk '
22-
/^\[workspace\.package\]/ { w = 1; next }
23-
w && /^\[/ { w = 0 }
24-
w && /^version[[:space:]]*=/ {
25-
line = $0
26-
sub(/^[^"]*"/, "", line)
27-
sub(/".*/, "", line)
28-
print line
29-
exit
30-
}
31-
'
32-
}
21+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
22+
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." >/dev/null 2>&1 && pwd)"
3323

34-
# Effective [package] version: explicit "x.y.z" or "__WS__" if version.workspace = true.
35-
package_version_kind() {
36-
awk '
37-
/^\[package\]/ { p = 1; next }
38-
p && /^\[/ { p = 0 }
39-
p && /^version\.workspace[[:space:]]*=[[:space:]]*true/ { print "__WS__"; exit }
40-
p && /^version[[:space:]]*=/ && $0 !~ /version\.workspace/ {
41-
line = $0
42-
sub(/^[^"]*"/, "", line)
43-
sub(/".*/, "", line)
44-
print line
45-
exit
46-
}
47-
'
48-
}
24+
tmp_root="$(mktemp -d)"
25+
base_dir="${tmp_root}/base"
26+
head_dir="${tmp_root}/head"
4927

50-
effective_package_version() {
51-
local manifest_content="$1"
52-
local workspace_content="$2"
53-
local kind
54-
kind=$(printf '%s' "$manifest_content" | package_version_kind)
55-
if [ "$kind" = "__WS__" ]; then
56-
printf '%s' "$workspace_content" | workspace_package_version
57-
return
58-
fi
59-
printf '%s' "$kind"
28+
cleanup() {
29+
# best-effort cleanup
30+
git -C "${REPO_ROOT}" worktree remove --force "${base_dir}" >/dev/null 2>&1 || true
31+
git -C "${REPO_ROOT}" worktree remove --force "${head_dir}" >/dev/null 2>&1 || true
32+
rm -rf "${tmp_root}" >/dev/null 2>&1 || true
6033
}
34+
trap cleanup EXIT
6135

62-
excluded_crate() {
63-
local n="$1"
64-
case "$n" in
65-
libdd-*-ffi) return 0 ;;
66-
datadog-*) return 0 ;;
67-
bin_tests | tools | sidecar_mockgen | cc_utils | spawn_worker | symbolizer-ffi | test_spawn_from_lib | build_common | build-common | builder)
68-
return 0
69-
;;
70-
esac
71-
return 1
72-
}
73-
74-
workspace_old=$(git show "${GIT_VERSION_BASE}:Cargo.toml" 2>/dev/null || true)
75-
workspace_new=$(git show "${GIT_VERSION_HEAD}:Cargo.toml" 2>/dev/null || { cat Cargo.toml; })
76-
77-
METADATA=$(cargo metadata --format-version=1 --no-deps)
78-
WORKSPACE_ROOT=$(echo "$METADATA" | jq -r '.workspace_root')
36+
# Ensure refs exist locally for worktree add.
37+
git -C "${REPO_ROOT}" fetch --no-tags origin >/dev/null 2>&1 || true
7938

80-
declare -A emit=()
39+
git -C "${REPO_ROOT}" worktree add --detach "${base_dir}" "${GIT_VERSION_BASE}" >/dev/null
40+
git -C "${REPO_ROOT}" worktree add --detach "${head_dir}" "${GIT_VERSION_HEAD}" >/dev/null
8141

82-
while IFS=$'\t' read -r name mpath; do
83-
[ -z "$name" ] && continue
84-
relpath=${mpath#"$WORKSPACE_ROOT/"}
42+
BASE_METADATA="$(cargo metadata --manifest-path "${base_dir}/Cargo.toml" --format-version=1 --no-deps)"
43+
HEAD_METADATA="$(cargo metadata --manifest-path "${head_dir}/Cargo.toml" --format-version=1 --no-deps)"
8544

86-
old_m=$(git show "${GIT_VERSION_BASE}:${relpath}" 2>/dev/null || true)
87-
new_m=$(git show "${GIT_VERSION_HEAD}:${relpath}" 2>/dev/null || true)
88-
[ -n "$new_m" ] || continue
89-
90-
v_old=""
91-
if [ -n "$old_m" ]; then
92-
v_old=$(effective_package_version "$old_m" "$workspace_old")
93-
fi
94-
v_new=$(effective_package_version "$new_m" "$workspace_new")
95-
96-
if [ "$v_old" = "$v_new" ]; then
97-
continue
98-
fi
99-
100-
if excluded_crate "$name"; then
101-
continue
102-
fi
103-
emit["$name"]=1
104-
done < <(echo "$METADATA" | jq -r '.packages[] | "\(.name)\t\(.manifest_path)"')
105-
106-
if [ "${#emit[@]}" -eq 0 ]; then
107-
echo "crates-to-package.sh: no packages with a changed [package] version between refs (nothing to emit)." >&2
45+
# Build a name -> {version, publishable} map for workspace members.
46+
#
47+
# publishable:
48+
# - publish unset (null) => publishable
49+
# - publish array (registries) => publishable if non-empty
50+
# - publish = false => NOT publishable
51+
map_filter='
52+
. as $m
53+
| ($m.packages | map({id, name, version, publish})) as $pkgs
54+
| ($m.workspace_members) as $members
55+
| [ $members[]
56+
| . as $id
57+
| ($pkgs[] | select(.id == $id))
58+
| {
59+
name,
60+
version,
61+
publishable: (
62+
if (.publish == null) then true
63+
elif (.publish | type) == "array" then ((.publish | length) > 0)
64+
else false
65+
end
66+
)
67+
}
68+
]
69+
| map({key: .name, value: {version: .version, publishable: .publishable}})
70+
| from_entries
71+
'
72+
73+
BASE_MAP="$(echo "${BASE_METADATA}" | jq -c "${map_filter}")"
74+
HEAD_MAP="$(echo "${HEAD_METADATA}" | jq -c "${map_filter}")"
75+
76+
# Emit publishable crates whose version changed between base and head.
77+
#
78+
# - If a crate is new in head (missing in base), include it.
79+
# - If a crate disappeared in head, ignore it.
80+
TO_PACKAGE="$(jq -nr --argjson base "${BASE_MAP}" --argjson head "${HEAD_MAP}" '
81+
($head | keys_unsorted) as $names
82+
| [ $names[]
83+
| . as $n
84+
| ($head[$n]) as $h
85+
| select($h.publishable == true)
86+
| ($base[$n].version // null) as $bv
87+
| ($h.version) as $hv
88+
| select($bv != $hv)
89+
| $n
90+
]
91+
| sort
92+
| .[]
93+
')"
94+
95+
if [ -z "${TO_PACKAGE}" ]; then
96+
echo "crates-to-package.sh: no publishable workspace crates had a version change between refs (nothing to emit)." >&2
10897
exit 0
10998
fi
11099

111-
for n in "${!emit[@]}"; do
112-
echo "$n"
113-
done | sort -u
100+
echo "${TO_PACKAGE}"

scripts/publication-order.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
# Usage: ./publication-order.sh [OPTIONS] [CRATE...]
99
#
1010
# If crate names are provided, shows only those crates and their dependencies in publication order.
11+
#
12+
# Important: this script is used by libddprof-build gitlab pipeline
1113

1214
set -euo pipefail
1315

0 commit comments

Comments
 (0)