Skip to content

Commit 2b3b9ea

Browse files
Merge pull request #213 from mavlink/ci-automate-release
ci: more automation
2 parents 3262a19 + 0c35e90 commit 2b3b9ea

File tree

4 files changed

+243
-14
lines changed

4 files changed

+243
-14
lines changed

.github/workflows/main.yml

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
name: MAVSDK-Java
2-
32
on:
43
push:
54
branches:
@@ -9,14 +8,40 @@ on:
98
- '**'
109
release:
1110
types: [created]
12-
1311
jobs:
14-
main:
12+
build:
13+
if: github.event_name != 'release'
1514
runs-on: ubuntu-24.04
1615
steps:
1716
- uses: actions/checkout@v4
1817
with:
1918
submodules: recursive
19+
- name: Build and prepare mavsdk
20+
working-directory: ./sdk
21+
run: |
22+
set -o pipefail
23+
python3 -m venv venv
24+
source ./venv/bin/activate
25+
pip install protoc-gen-mavsdk
26+
./gradlew build
27+
- name: Build and prepare mavsdk-server
28+
working-directory: ./mavsdk_server
29+
run: ./gradlew build
30+
31+
release:
32+
if: github.event_name == 'release' && github.event.action == 'created'
33+
runs-on: ubuntu-24.04
34+
steps:
35+
- uses: actions/checkout@v4
36+
with:
37+
submodules: recursive
38+
- name: Validate version
39+
id: version
40+
run: |
41+
set -o pipefail
42+
tag_name="${{ github.ref_name }}"
43+
python ./tools/version_validator.py "$tag_name"
44+
echo "tag_name=$tag_name" >> $GITHUB_OUTPUT
2045
- name: Prepare tokens keystore
2146
run: |
2247
echo "${{ secrets.TOKENS_KEYSTORE }}" > /tmp/keystore.properties.b64
@@ -25,27 +50,49 @@ jobs:
2550
cp /tmp/keystore.properties mavsdk_server
2651
- name: Prepare GPG key
2752
run: echo "${{ secrets.SIGNING_PGP_KEY }}" | gpg --batch --import
53+
- name: Extract version and sync proto submodule
54+
run: |
55+
set -o pipefail
56+
tag_name="${{ steps.version.outputs.tag_name }}"
57+
58+
# Extract version number
59+
extracted_version=$(python ./tools/version_validator.py -e "$tag_name")
60+
61+
# Clone MAVSDK repo with minimal depth to get proto submodule hash
62+
git clone --depth 1 --branch "${extracted_version}" https://github.com/mavlink/mavsdk.git /tmp/mavsdk
63+
64+
# Get the proto submodule commit hash from the MAVSDK repo
65+
cd /tmp/mavsdk
66+
proto_commit_hash=$(git ls-tree HEAD proto | awk '{print $3}')
67+
68+
# Update our local proto submodule to match
69+
cd $GITHUB_WORKSPACE/sdk/proto
70+
git fetch origin
71+
git checkout $proto_commit_hash
72+
73+
# Cleanup
74+
rm -rf /tmp/mavsdk
75+
76+
echo "Updated proto submodule to commit: $proto_commit_hash for MAVSDK version: $extracted_version"
2877
- name: Build and prepare mavsdk
2978
working-directory: ./sdk
3079
run: |
3180
set -o pipefail
3281
python3 -m venv venv
3382
source ./venv/bin/activate
3483
pip install protoc-gen-mavsdk
35-
./gradlew build
36-
./gradlew publish
84+
./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }}
85+
./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }}
3786
- name: Build and prepare mavsdk-server
3887
working-directory: ./mavsdk_server
3988
run: |
4089
set -o pipefail
41-
./gradlew build
42-
./gradlew publish
90+
./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }}
91+
./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }}
4392
- name: Deploy mavsdk
44-
if: github.event_name == 'release' && github.event.action == 'created'
4593
working-directory: ./sdk
46-
run: ./gradlew jreleaserDeploy
94+
run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }}
4795
- name: Deploy mavsdk-server
48-
if: github.event_name == 'release' && github.event.action == 'created'
4996
working-directory: ./mavsdk_server
50-
run: ./gradlew jreleaserDeploy
97+
run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }}
5198

mavsdk_server/build.gradle.kts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,17 @@ try {
2222
}
2323

2424
allprojects {
25-
val mavsdk_server_release = "v3.6.0"
25+
// We fetch the mavsdk_server binary that corresponds to the mavsdk-java
26+
// version. Say we set this package to be 3.6.0-2-SNAPSHOT, it means that it
27+
// corresponds to mavsdk_server 3.6.0.
28+
val mavsdk_server_release = if (!project.hasProperty("VERSION")) {
29+
"v3.6.0"
30+
} else {
31+
val versionString = project.property("VERSION").toString()
32+
val regex = Regex("v?(\\d+\\.\\d+\\.\\d+)")
33+
val version = regex.find(versionString)?.groupValues?.get(1)
34+
"v$version"
35+
}
2636

2737
tasks {
2838
register<Copy>("extractMavsdkServer") {
@@ -87,8 +97,13 @@ android {
8797
minSdk = 21
8898

8999
group = "io.mavsdk"
90-
version = "3.6.0"
91100

101+
// The version must be of the form "X.Y.Z-b[-SNAPSHOT]", where "X.Y.Z"
102+
// is the MAVSDK-C++ version, "b" is the build number of this
103+
// MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT.
104+
version =
105+
if (project.hasProperty("VERSION")) project.property("VERSION").toString()
106+
else "3.6.0-SNAPSHOT"
92107

93108
ndk {
94109
abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64")

sdk/build.gradle.kts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@ try {
2222
}
2323

2424
group = "io.mavsdk"
25-
version = "3.6.0"
25+
26+
// The version must be of the form "X.Y.Z-b[-SNAPSHOT]", where "X.Y.Z"
27+
// is the MAVSDK-C++ version, "b" is the build number of this
28+
// MAVSDK-Java package and "SNAPSHOT" optionally sets it as a SNAPSHOT.
29+
// For instance, if the version is 3.6.0-2, it should be built with the same
30+
// version of the proto files as MAVSDK-C++ v3.6.0.
31+
version =
32+
if (project.hasProperty("VERSION")) project.property("VERSION").toString()
33+
else "3.6.0-SNAPSHOT"
2634

2735
val grpcVersion = "1.61.1"
2836

tools/version_validator.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Version Number Validator
4+
5+
This script validates version numbers and extracts major.minor.patch format.
6+
7+
Version format rules:
8+
- Can start with 'v' (optional): v2.3.1 or 2.3.1
9+
- Must have major.minor.patch: 1.2.3 (minimum required)
10+
- May have build number: 1.2.3-1 or 1.2.3-2
11+
- May end with -SNAPSHOT: 3.4.5-1-SNAPSHOT or 3.4.5-SNAPSHOT
12+
13+
Usage:
14+
python version_validator.py <version_string>
15+
python version_validator.py --extract <version_string>
16+
"""
17+
18+
import re
19+
import sys
20+
import argparse
21+
22+
def extract_major_minor_patch(version_string):
23+
"""
24+
Extract major.minor.patch from a valid version string in vX.Y.Z format.
25+
26+
Args:
27+
version_string (str): The version string to extract from
28+
29+
Returns:
30+
str: The extracted version in vX.Y.Z format, or None if invalid
31+
"""
32+
# Define the regex pattern for valid version strings
33+
pattern = r'^v?(\d+)\.(\d+)\.(\d+)(?:-(\d+))?(?:-SNAPSHOT)?$'
34+
match = re.match(pattern, version_string)
35+
36+
if match:
37+
major, minor, patch = match.groups()[:3]
38+
return f"v{major}.{minor}.{patch}"
39+
40+
return None
41+
42+
def validate_version(version_string):
43+
"""
44+
Validate a version string according to the specified rules.
45+
46+
Args:
47+
version_string (str): The version string to validate
48+
49+
Returns:
50+
bool: True if valid, False otherwise
51+
"""
52+
return extract_major_minor_patch(version_string) is not None
53+
54+
def main():
55+
parser = argparse.ArgumentParser(
56+
description="Validate version number and extract major.minor.patch format",
57+
formatter_class=argparse.RawDescriptionHelpFormatter,
58+
epilog="""
59+
Examples:
60+
python version_validator.py v2.3.1 # Validate version
61+
python version_validator.py 1.2.3-1 # Validate version with build
62+
python version_validator.py --extract v2.3.1-SNAPSHOT # Extract v2.3.1
63+
python version_validator.py -e 3.4.5-2-SNAPSHOT # Extract v3.4.5
64+
65+
Valid version formats:
66+
v1.2.3, 1.2.3, v1.2.3-1, 1.2.3-1, v1.2.3-SNAPSHOT, 1.2.3-1-SNAPSHOT
67+
"""
68+
)
69+
70+
parser.add_argument(
71+
'version',
72+
help='Version string to validate/extract'
73+
)
74+
parser.add_argument(
75+
'-e', '--extract',
76+
action='store_true',
77+
help='Extract major.minor.patch in vX.Y.Z format'
78+
)
79+
80+
args = parser.parse_args()
81+
82+
if args.extract:
83+
# Extract mode
84+
result = extract_major_minor_patch(args.version)
85+
if result:
86+
print(result)
87+
sys.exit(0)
88+
else:
89+
print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr)
90+
sys.exit(1)
91+
else:
92+
# Validation mode
93+
if validate_version(args.version):
94+
print(f"'{args.version}' is a valid version string")
95+
sys.exit(0)
96+
else:
97+
print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr)
98+
sys.exit(1)
99+
100+
101+
if __name__ == "__main__":
102+
# If no arguments provided, run some test cases
103+
if len(sys.argv) == 1:
104+
print("Running test cases...")
105+
106+
test_cases = [
107+
# Valid cases
108+
("v2.3.1", True),
109+
("2.3.1", True),
110+
("1.2.3-1", True),
111+
("v1.2.3-1", True),
112+
("3.4.5-SNAPSHOT", True),
113+
("v3.4.5-SNAPSHOT", True),
114+
("1.2.3-1-SNAPSHOT", True),
115+
("v1.2.3-1-SNAPSHOT", True),
116+
("10.20.30", True),
117+
("v0.0.1", True),
118+
119+
# Invalid cases
120+
("1.2", False),
121+
("v1.2", False),
122+
("1.2.3.4", False),
123+
("v1.2.3.4", False),
124+
("1.2.3-", False),
125+
("1.2.3-SNAPSHOT-1", False),
126+
("1.2.3-a", False),
127+
("v1.2.3-a", False),
128+
("av1.2.3", False),
129+
("a1.2.3", False),
130+
(" v1.2.3", False),
131+
("V1.2.3-a", False),
132+
("1.2.x", False),
133+
("", False),
134+
("v", False),
135+
("1.2.3-1-SNAPSHOT-extra", False),
136+
]
137+
138+
print("\nValidation Tests:")
139+
for version, expected in test_cases:
140+
result = validate_version(version)
141+
status = "✓" if result == expected else "✗"
142+
print(f"{status} {version:<25} -> {result} (expected {expected})")
143+
144+
print("\nExtraction Tests:")
145+
extraction_tests = [
146+
("v2.3.1", "v2.3.1"),
147+
("2.3.1", "v2.3.1"),
148+
("1.2.3-1", "v1.2.3"),
149+
("v1.2.3-1-SNAPSHOT", "v1.2.3"),
150+
("3.4.5-SNAPSHOT", "v3.4.5"),
151+
("invalid", None),
152+
]
153+
154+
for version, expected in extraction_tests:
155+
result = extract_major_minor_patch(version)
156+
status = "✓" if result == expected else "✗"
157+
print(f"{status} {version:<25} -> {result} (expected {expected})")
158+
else:
159+
main()

0 commit comments

Comments
 (0)