Skip to content

Commit c0938e6

Browse files
Factor branch parsing logic
Add shared branch family/suite resolver script. Reuse it in pkg-build and pkg-release workflows. Update docs for last-two-segments parsing rule. Signed-off-by: Simon Beaudoin <sbeaudoi@qti.qualcomm.com>
1 parent 8a56e68 commit c0938e6

7 files changed

Lines changed: 187 additions & 96 deletions

File tree

.github/workflows/pkg-build-reusable-workflow.yml

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ jobs:
123123
force_docker_build: ${{ steps.resolve.outputs.force_docker_build }}
124124
suite: ${{ steps.resolve.outputs.suite }}
125125
steps:
126+
- name: Checkout qcom-build-utils scripts
127+
uses: actions/checkout@v5
128+
with:
129+
repository: qualcomm-linux/qcom-build-utils
130+
ref: ${{ inputs.qcom-build-utils-ref }}
131+
path: qcom-build-utils
132+
126133
- name: Resolve family and suite from branch
127134
id: resolve
128135
shell: bash
@@ -134,61 +141,40 @@ jobs:
134141
run: |
135142
set -euo pipefail
136143
137-
normalize_ref() {
138-
local ref="$1"
139-
if [[ "$ref" == refs/heads/* ]]; then
140-
ref="${ref#refs/heads/}"
141-
fi
142-
if [[ "$ref" == refs/remotes/* ]]; then
143-
ref="${ref#refs/remotes/}"
144-
fi
145-
if [[ "$ref" == origin/* ]]; then
146-
ref="${ref#origin/}"
147-
fi
148-
printf '%s\n' "$ref"
144+
RESOLVER_SCRIPT="${GITHUB_WORKSPACE}/qcom-build-utils/scripts/resolve_branch_family_suite.sh"
145+
146+
parse_resolved_values() {
147+
local resolved_kv="$1"
148+
local key value
149+
150+
normalized_ref=""
151+
family=""
152+
suite=""
153+
while IFS='=' read -r key value; do
154+
case "$key" in
155+
normalized_ref) normalized_ref="$value" ;;
156+
family) family="$value" ;;
157+
suite) suite="$value" ;;
158+
esac
159+
done <<< "$resolved_kv"
149160
}
150161
151-
resolve_from_ref() {
152-
local ref="$1"
153-
local -n out_family="$2"
154-
local -n out_suite="$3"
155-
local -a ref_parts
156-
157-
IFS='/' read -r -a ref_parts <<< "$ref"
158-
if (( ${#ref_parts[@]} < 3 )); then
159-
return 1
160-
fi
161-
162-
local family_idx suite_idx
163-
family_idx=$((${#ref_parts[@]} - 2))
164-
suite_idx=$((${#ref_parts[@]} - 1))
165-
out_family="${ref_parts[$family_idx]}"
166-
out_suite="${ref_parts[$suite_idx]}"
167-
168-
case "$out_family" in
169-
debian|ubuntu)
170-
return 0
171-
;;
172-
*)
173-
return 1
174-
;;
175-
esac
176-
}
177-
178-
normalized_ref="$(normalize_ref "$DEBIAN_REF_INPUT")"
179-
source_ref="$normalized_ref"
180-
if ! resolve_from_ref "$normalized_ref" family suite; then
162+
source_ref=""
163+
if resolved_kv="$("$RESOLVER_SCRIPT" "$DEBIAN_REF_INPUT")"; then
164+
parse_resolved_values "$resolved_kv"
165+
source_ref="$normalized_ref"
166+
else
181167
if [[ -n "$BASE_REF_INPUT" ]]; then
182-
normalized_base_ref="$(normalize_ref "$BASE_REF_INPUT")"
183-
if resolve_from_ref "$normalized_base_ref" family suite; then
184-
source_ref="$normalized_base_ref"
185-
echo "::warning::debian-ref '$DEBIAN_REF_INPUT' does not match '<prefix>/<family>/<suite>'; falling back to base-ref '$BASE_REF_INPUT' for suite routing."
168+
if resolved_kv="$("$RESOLVER_SCRIPT" "$BASE_REF_INPUT")"; then
169+
parse_resolved_values "$resolved_kv"
170+
source_ref="$normalized_ref"
171+
echo "::warning::debian-ref '$DEBIAN_REF_INPUT' does not end with '/<family>/<suite>'; falling back to base-ref '$BASE_REF_INPUT' for suite routing."
186172
else
187-
echo "::error::Unable to resolve build target from debian-ref '$DEBIAN_REF_INPUT' or base-ref '$BASE_REF_INPUT'. Expected '<prefix>/<family>/<suite>' such as 'qcom/ubuntu/resolute'."
173+
echo "::error::Unable to resolve build target from debian-ref '$DEBIAN_REF_INPUT' or base-ref '$BASE_REF_INPUT'. Expected a branch ending in '/<family>/<suite>' (for example 'ubuntu/resolute' or 'qcom/ubuntu/resolute')."
188174
exit 1
189175
fi
190176
else
191-
echo "::error::Unable to resolve build target from debian-ref '$DEBIAN_REF_INPUT'. Expected '<prefix>/<family>/<suite>' such as 'qcom/ubuntu/resolute'."
177+
echo "::error::Unable to resolve build target from debian-ref '$DEBIAN_REF_INPUT'. Expected a branch ending in '/<family>/<suite>' (for example 'ubuntu/resolute' or 'qcom/ubuntu/resolute')."
192178
exit 1
193179
fi
194180
fi

.github/workflows/pkg-release-reusable-workflow.yml

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -67,61 +67,37 @@ jobs:
6767
run:
6868
shell: bash
6969
steps:
70+
- name: Checkout qcom-build-utils scripts
71+
uses: actions/checkout@v5
72+
with:
73+
repository: qualcomm-linux/qcom-build-utils
74+
ref: ${{ inputs.qcom-build-utils-ref }}
75+
path: qcom-build-utils
76+
7077
- name: Resolve family and suite from branch
7178
id: resolve
7279
env:
7380
DEBIAN_REF_INPUT: ${{ inputs.debian-branch }}
7481
run: |
7582
set -euo pipefail
7683
77-
normalize_ref() {
78-
local ref="$1"
79-
if [[ "$ref" == refs/heads/* ]]; then
80-
ref="${ref#refs/heads/}"
81-
fi
82-
if [[ "$ref" == refs/remotes/* ]]; then
83-
ref="${ref#refs/remotes/}"
84-
fi
85-
if [[ "$ref" == origin/* ]]; then
86-
ref="${ref#origin/}"
87-
fi
88-
printf '%s\n' "$ref"
89-
}
90-
91-
resolve_from_ref() {
92-
local ref="$1"
93-
local -n out_family="$2"
94-
local -n out_suite="$3"
95-
local -a ref_parts
96-
97-
IFS='/' read -r -a ref_parts <<< "$ref"
98-
if (( ${#ref_parts[@]} < 3 )); then
99-
return 1
100-
fi
101-
102-
local family_idx suite_idx
103-
family_idx=$((${#ref_parts[@]} - 2))
104-
suite_idx=$((${#ref_parts[@]} - 1))
105-
out_family="${ref_parts[$family_idx]}"
106-
out_suite="${ref_parts[$suite_idx]}"
107-
108-
case "$out_family" in
109-
debian|ubuntu)
110-
return 0
111-
;;
112-
*)
113-
return 1
114-
;;
115-
esac
116-
}
117-
118-
normalized_ref="$(normalize_ref "$DEBIAN_REF_INPUT")"
119-
120-
if ! resolve_from_ref "$normalized_ref" family suite; then
121-
echo "::error::Unable to resolve release target from debian-branch '$DEBIAN_REF_INPUT'. Expected '<prefix>/<family>/<suite>' such as 'qcom/ubuntu/resolute'."
84+
RESOLVER_SCRIPT="${GITHUB_WORKSPACE}/qcom-build-utils/scripts/resolve_branch_family_suite.sh"
85+
if ! resolved_kv="$("$RESOLVER_SCRIPT" "$DEBIAN_REF_INPUT")"; then
86+
echo "::error::Unable to resolve release target from debian-branch '$DEBIAN_REF_INPUT'. Expected a branch ending in '/<family>/<suite>' (for example 'ubuntu/resolute' or 'qcom/ubuntu/resolute')."
12287
exit 1
12388
fi
12489
90+
normalized_ref=""
91+
family=""
92+
suite=""
93+
while IFS='=' read -r key value; do
94+
case "$key" in
95+
normalized_ref) normalized_ref="$value" ;;
96+
family) family="$value" ;;
97+
suite) suite="$value" ;;
98+
esac
99+
done <<< "$resolved_kv"
100+
125101
if [[ "$family" == "debian" ]] && [[ "$suite" == "latest" || "$suite" == "unstable" ]]; then
126102
suite=sid
127103
fi

AGENTS.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ orchestration around build, test, promotion, and release flows.
4040
## Build Branch Convention (Caller Contract)
4141

4242
For `pkg-build-reusable-workflow.yml`, callers should pass a `debian-ref` branch
43-
name that ends with:
43+
name where the last two `/`-delimited fields are:
4444

4545
- `<family>/<suite>`
4646

@@ -54,6 +54,15 @@ Examples:
5454
- `qcom/debian/latest` (normalized to suite `sid`)
5555
- `qcom/debian/bookworm`
5656
- `qcom/ubuntu/resolute`
57+
- `test/qcom/ubuntu/resolute`
58+
- `ubuntu/resolute`
59+
- `dev/whatever/yo/debian/trixie`
60+
61+
Invalid examples:
62+
63+
- `resolute`
64+
- `ubuntu`
65+
- `ubuntu-resolute`
5766

5867
`pkg-build-reusable-workflow.yml` no longer takes a separate `suite` input for
5968
routing; it resolves family/suite from `debian-ref`.

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,25 @@ Package repositories call these workflows from their own `.github/workflows/` di
8686
`pkg-build-reusable-workflow.yml` now resolves `family` and `suite` from the
8787
`debian-ref` branch name instead of taking a separate `suite` input.
8888

89-
Expected branch pattern:
89+
Branch parsing rule:
9090

91-
- `<prefix>/<family>/<suite>`
91+
- take the last two `/`-delimited fields as `<family>/<suite>`
9292
- `family` must be `debian` or `ubuntu`
9393

9494
Examples:
9595

9696
- `qcom/debian/latest` (maps to `sid`)
9797
- `qcom/debian/bookworm`
9898
- `qcom/ubuntu/resolute`
99+
- `test/qcom/ubuntu/resolute`
100+
- `ubuntu/resolute`
101+
- `dev/whatever/yo/debian/trixie`
102+
103+
Invalid examples:
104+
105+
- `resolute`
106+
- `ubuntu`
107+
- `ubuntu-resolute`
99108

100109
For PR jobs that build transient heads (for example `debian/pr/*`), workflow
101110
routing falls back to the PR base branch (`github.base_ref`).

docs/reusable-workflows.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ flowchart TD
6969
| `srcpkg_name` | Source package name |
7070
| `srcpkg_version` | Source package version |
7171

72+
### Branch Parsing Rule (`debian-ref`)
73+
74+
- The resolver splits the normalized branch name on `/`.
75+
- It takes the last two fields as `<family>/<suite>`.
76+
- `family` must be `debian` or `ubuntu`.
77+
78+
Valid examples:
79+
80+
- `qcom/ubuntu/resolute` -> `family=ubuntu`, `suite=resolute`
81+
- `test/qcom/ubuntu/resolute` -> `family=ubuntu`, `suite=resolute`
82+
- `ubuntu/resolute` -> `family=ubuntu`, `suite=resolute`
83+
- `dev/whatever/yo/debian/trixie` -> `family=debian`, `suite=trixie`
84+
85+
Invalid examples:
86+
87+
- `resolute`
88+
- `ubuntu`
89+
- `ubuntu-resolute`
90+
7291
### Workflow Steps
7392

7493
1. **Resolve suite family**: Normalize the caller input and decide whether the run is Debian or Ubuntu
@@ -135,6 +154,10 @@ flowchart TD
135154
| `test-run` | boolean | No | `true` | Debian: stop after Debusine build/test. Ubuntu: still stateful, but upload to test/proposed destination based on this input |
136155
| `debusine-parent-workspace` | string | No | `ci` | Parent Debusine workspace passed through to the Debian build/test phase |
137156

157+
`debian-branch` uses the same parsing rule as `debian-ref` in the build
158+
reusable workflow: split on `/`, take the last two fields as
159+
`<family>/<suite>`, and require `family` to be `debian` or `ubuntu`.
160+
138161
### Secrets
139162

140163
| Secret | Required | Description |

scripts/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,28 @@ Shell script for merging upstream changes into Debian packaging branch.
132132
./scripts/merge_debian_packaging_upstream upstream/main
133133
```
134134

135+
### 4. resolve_branch_family_suite.sh
136+
137+
Helper used by reusable workflows to resolve `family`/`suite` from branch-like refs.
138+
139+
**Rule:**
140+
- Normalize refs like `refs/heads/*`, `refs/remotes/*`, and `origin/*`
141+
- Split by `/`
142+
- Take the last two fields as `<family>/<suite>`
143+
- Require `family` to be `debian` or `ubuntu`
144+
145+
**Usage:**
146+
```bash
147+
./scripts/resolve_branch_family_suite.sh <ref>
148+
```
149+
150+
**Output:**
151+
```text
152+
normalized_ref=<normalized-ref>
153+
family=<debian|ubuntu>
154+
suite=<suite>
155+
```
156+
135157
## Common Workflows
136158

137159
### Building a Single Package
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env bash
2+
# Resolve distro family/suite from a branch-like ref.
3+
# The last two '/'-delimited fields are interpreted as "<family>/<suite>".
4+
5+
set -euo pipefail
6+
7+
normalize_ref() {
8+
local ref="$1"
9+
10+
if [[ "$ref" == refs/heads/* ]]; then
11+
ref="${ref#refs/heads/}"
12+
fi
13+
if [[ "$ref" == refs/remotes/* ]]; then
14+
ref="${ref#refs/remotes/}"
15+
fi
16+
if [[ "$ref" == origin/* ]]; then
17+
ref="${ref#origin/}"
18+
fi
19+
20+
printf '%s\n' "$ref"
21+
}
22+
23+
resolve_from_ref() {
24+
local ref="$1"
25+
local -n out_family="$2"
26+
local -n out_suite="$3"
27+
local -a ref_parts
28+
29+
IFS='/' read -r -a ref_parts <<< "$ref"
30+
if (( ${#ref_parts[@]} < 2 )); then
31+
return 1
32+
fi
33+
34+
out_family="${ref_parts[$((${#ref_parts[@]} - 2))]}"
35+
out_suite="${ref_parts[$((${#ref_parts[@]} - 1))]}"
36+
37+
case "$out_family" in
38+
debian|ubuntu)
39+
return 0
40+
;;
41+
*)
42+
return 1
43+
;;
44+
esac
45+
}
46+
47+
main() {
48+
if (( $# != 1 )); then
49+
echo "Usage: $0 <ref>" >&2
50+
exit 2
51+
fi
52+
53+
local input_ref="$1"
54+
local normalized_ref family suite
55+
56+
normalized_ref="$(normalize_ref "$input_ref")"
57+
if ! resolve_from_ref "$normalized_ref" family suite; then
58+
exit 1
59+
fi
60+
61+
printf 'normalized_ref=%s\n' "$normalized_ref"
62+
printf 'family=%s\n' "$family"
63+
printf 'suite=%s\n' "$suite"
64+
}
65+
66+
main "$@"

0 commit comments

Comments
 (0)