|
2 | 2 | # Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ |
3 | 3 | # SPDX-License-Identifier: Apache-2.0 |
4 | 4 | # |
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. |
9 | 7 | # |
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 |
13 | 15 |
|
14 | 16 | set -euo pipefail |
15 | 17 |
|
16 | 18 | GIT_VERSION_BASE="${GIT_VERSION_BASE:-origin/main}" |
17 | 19 | GIT_VERSION_HEAD="${GIT_VERSION_HEAD:-HEAD}" |
18 | 20 |
|
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)" |
33 | 23 |
|
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" |
49 | 27 |
|
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 |
60 | 33 | } |
| 34 | +trap cleanup EXIT |
61 | 35 |
|
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 |
79 | 38 |
|
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 |
81 | 41 |
|
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)" |
85 | 44 |
|
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 |
108 | 97 | exit 0 |
109 | 98 | fi |
110 | 99 |
|
111 | | -for n in "${!emit[@]}"; do |
112 | | - echo "$n" |
113 | | -done | sort -u |
| 100 | +echo "${TO_PACKAGE}" |
0 commit comments