Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 58 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
name: MAVSDK-Java

on:
push:
branches:
Expand All @@ -9,14 +8,40 @@ on:
- '**'
release:
types: [created]

jobs:
main:
build:
if: github.event_name != 'release'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Build and prepare mavsdk
working-directory: ./sdk
run: |
set -o pipefail
python3 -m venv venv
source ./venv/bin/activate
pip install protoc-gen-mavsdk
./gradlew build
- name: Build and prepare mavsdk-server
working-directory: ./mavsdk_server
run: ./gradlew build

release:
if: github.event_name == 'release' && github.event.action == 'created'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Validate version
id: version
run: |
set -o pipefail
tag_name="${{ github.ref_name }}"
python ./tools/version_validator.py "$tag_name"
echo "tag_name=$tag_name" >> $GITHUB_OUTPUT
- name: Prepare tokens keystore
run: |
echo "${{ secrets.TOKENS_KEYSTORE }}" > /tmp/keystore.properties.b64
Expand All @@ -25,27 +50,49 @@ jobs:
cp /tmp/keystore.properties mavsdk_server
- name: Prepare GPG key
run: echo "${{ secrets.SIGNING_PGP_KEY }}" | gpg --batch --import
- name: Extract version and sync proto submodule
run: |
set -o pipefail
tag_name="${{ steps.version.outputs.tag_name }}"

# Extract version number
extracted_version=$(python ./tools/version_validator.py -e "$tag_name")

# Clone MAVSDK repo with minimal depth to get proto submodule hash
git clone --depth 1 --branch "${extracted_version}" https://github.com/mavlink/mavsdk.git /tmp/mavsdk

# Get the proto submodule commit hash from the MAVSDK repo
cd /tmp/mavsdk
proto_commit_hash=$(git ls-tree HEAD proto | awk '{print $3}')

# Update our local proto submodule to match
cd $GITHUB_WORKSPACE/sdk/proto
git fetch origin
git checkout $proto_commit_hash

# Cleanup
rm -rf /tmp/mavsdk

echo "Updated proto submodule to commit: $proto_commit_hash for MAVSDK version: $extracted_version"
- name: Build and prepare mavsdk
working-directory: ./sdk
run: |
set -o pipefail
python3 -m venv venv
source ./venv/bin/activate
pip install protoc-gen-mavsdk
./gradlew build
./gradlew publish
./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }}
./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }}
- name: Build and prepare mavsdk-server
working-directory: ./mavsdk_server
run: |
set -o pipefail
./gradlew build
./gradlew publish
./gradlew build -PVERSION=${{ steps.version.outputs.tag_name }}
./gradlew publish -PVERSION=${{ steps.version.outputs.tag_name }}
- name: Deploy mavsdk
if: github.event_name == 'release' && github.event.action == 'created'
working-directory: ./sdk
run: ./gradlew jreleaserDeploy
run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }}
- name: Deploy mavsdk-server
if: github.event_name == 'release' && github.event.action == 'created'
working-directory: ./mavsdk_server
run: ./gradlew jreleaserDeploy
run: ./gradlew jreleaserDeploy -PVERSION=${{ steps.version.outputs.tag_name }}

19 changes: 17 additions & 2 deletions mavsdk_server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,17 @@ try {
}

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

tasks {
register<Copy>("extractMavsdkServer") {
Expand Down Expand Up @@ -87,8 +97,13 @@ android {
minSdk = 21

group = "io.mavsdk"
version = "3.6.0"

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

ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
Expand Down
10 changes: 9 additions & 1 deletion sdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ try {
}

group = "io.mavsdk"
version = "3.6.0"

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

val grpcVersion = "1.61.1"

Expand Down
159 changes: 159 additions & 0 deletions tools/version_validator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""
Version Number Validator

This script validates version numbers and extracts major.minor.patch format.

Version format rules:
- Can start with 'v' (optional): v2.3.1 or 2.3.1
- Must have major.minor.patch: 1.2.3 (minimum required)
- May have build number: 1.2.3-1 or 1.2.3-2
- May end with -SNAPSHOT: 3.4.5-1-SNAPSHOT or 3.4.5-SNAPSHOT

Usage:
python version_validator.py <version_string>
python version_validator.py --extract <version_string>
"""

import re
import sys
import argparse

def extract_major_minor_patch(version_string):
"""
Extract major.minor.patch from a valid version string in vX.Y.Z format.

Args:
version_string (str): The version string to extract from

Returns:
str: The extracted version in vX.Y.Z format, or None if invalid
"""
# Define the regex pattern for valid version strings
pattern = r'^v?(\d+)\.(\d+)\.(\d+)(?:-(\d+))?(?:-SNAPSHOT)?$'
match = re.match(pattern, version_string)

if match:
major, minor, patch = match.groups()[:3]
return f"v{major}.{minor}.{patch}"

return None

def validate_version(version_string):
"""
Validate a version string according to the specified rules.

Args:
version_string (str): The version string to validate

Returns:
bool: True if valid, False otherwise
"""
return extract_major_minor_patch(version_string) is not None

def main():
parser = argparse.ArgumentParser(
description="Validate version number and extract major.minor.patch format",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python version_validator.py v2.3.1 # Validate version
python version_validator.py 1.2.3-1 # Validate version with build
python version_validator.py --extract v2.3.1-SNAPSHOT # Extract v2.3.1
python version_validator.py -e 3.4.5-2-SNAPSHOT # Extract v3.4.5

Valid version formats:
v1.2.3, 1.2.3, v1.2.3-1, 1.2.3-1, v1.2.3-SNAPSHOT, 1.2.3-1-SNAPSHOT
"""
)

parser.add_argument(
'version',
help='Version string to validate/extract'
)
parser.add_argument(
'-e', '--extract',
action='store_true',
help='Extract major.minor.patch in vX.Y.Z format'
)

args = parser.parse_args()

if args.extract:
# Extract mode
result = extract_major_minor_patch(args.version)
if result:
print(result)
sys.exit(0)
else:
print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr)
sys.exit(1)
else:
# Validation mode
if validate_version(args.version):
print(f"'{args.version}' is a valid version string")
sys.exit(0)
else:
print(f"Error: '{args.version}' is not a valid version string", file=sys.stderr)
sys.exit(1)


if __name__ == "__main__":
# If no arguments provided, run some test cases
if len(sys.argv) == 1:
print("Running test cases...")

test_cases = [
# Valid cases
("v2.3.1", True),
("2.3.1", True),
("1.2.3-1", True),
("v1.2.3-1", True),
("3.4.5-SNAPSHOT", True),
("v3.4.5-SNAPSHOT", True),
("1.2.3-1-SNAPSHOT", True),
("v1.2.3-1-SNAPSHOT", True),
("10.20.30", True),
("v0.0.1", True),

# Invalid cases
("1.2", False),
("v1.2", False),
("1.2.3.4", False),
("v1.2.3.4", False),
("1.2.3-", False),
("1.2.3-SNAPSHOT-1", False),
("1.2.3-a", False),
("v1.2.3-a", False),
("av1.2.3", False),
("a1.2.3", False),
(" v1.2.3", False),
("V1.2.3-a", False),
("1.2.x", False),
("", False),
("v", False),
("1.2.3-1-SNAPSHOT-extra", False),
]

print("\nValidation Tests:")
for version, expected in test_cases:
result = validate_version(version)
status = "✓" if result == expected else "✗"
print(f"{status} {version:<25} -> {result} (expected {expected})")

print("\nExtraction Tests:")
extraction_tests = [
("v2.3.1", "v2.3.1"),
("2.3.1", "v2.3.1"),
("1.2.3-1", "v1.2.3"),
("v1.2.3-1-SNAPSHOT", "v1.2.3"),
("3.4.5-SNAPSHOT", "v3.4.5"),
("invalid", None),
]

for version, expected in extraction_tests:
result = extract_major_minor_patch(version)
status = "✓" if result == expected else "✗"
print(f"{status} {version:<25} -> {result} (expected {expected})")
else:
main()