Skip to content

Commit 55f8012

Browse files
committed
feat: Add release script and conanfile.py
- Create comprehensive release script (scripts/release.sh) - Validates version consistency across all configuration files - Checks git history for existing version tags - Prevents duplicate or lower version releases - Performs semantic version comparison - Supports dry-run mode with -n/--dry-run flag - Creates annotated git tags and pushes to remote - Provides clear feedback on each validation step - Add conanfile.py for Conan package manager support - Enables packaging with Conan C++ package manager - Version 1.3.2 aligned with other configuration files Release script workflow: 1. Extracts version from all source files 2. Validates version consistency 3. Checks git repository status 4. Queries git history for existing tags 5. Verifies version uniqueness 6. Compares version with latest release 7. Creates and pushes release tag Features: - Colored output for better readability - Comprehensive error checking at each step - Dry-run mode for testing without side effects - Version comparison using semantic versioning - Clear summary and next steps guidance
1 parent 88350d4 commit 55f8012

2 files changed

Lines changed: 378 additions & 0 deletions

File tree

conanfile.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from conan import ConanFile
2+
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
3+
from conan.tools.files import copy
4+
import os
5+
6+
class CcapConan(ConanFile):
7+
name = "ccap"
8+
version = "1.3.2"
9+
license = "MIT"
10+
author = "wysaid (this@wysaid.org)"
11+
url = "https://github.com/wysaid/CameraCapture"
12+
description = "A C/C++ library for camera capture"
13+
topics = ("camera", "capture", "video", "cpp")
14+
settings = "os", "compiler", "build_type", "arch"
15+
options = {
16+
"shared": [True, False],
17+
"fPIC": [True, False],
18+
"no_log": [True, False],
19+
}
20+
default_options = {
21+
"shared": False,
22+
"fPIC": True,
23+
"no_log": False,
24+
}
25+
26+
def config_options(self):
27+
if self.settings.os == "Windows":
28+
del self.options.fPIC
29+
30+
def layout(self):
31+
cmake_layout(self)
32+
33+
def generate(self):
34+
tc = CMakeToolchain(self)
35+
tc.variables["CCAP_BUILD_SHARED"] = self.options.shared
36+
tc.variables["CCAP_NO_LOG"] = self.options.no_log
37+
tc.variables["CCAP_BUILD_EXAMPLES"] = False
38+
tc.variables["CCAP_BUILD_TESTS"] = False
39+
tc.variables["CCAP_INSTALL"] = True
40+
tc.generate()
41+
42+
def build(self):
43+
cmake = CMake(self)
44+
cmake.configure()
45+
cmake.build()
46+
47+
def package(self):
48+
cmake = CMake(self)
49+
cmake.install()
50+
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
51+
52+
def package_info(self):
53+
self.cpp_info.libs = ["ccap"]
54+
55+
if self.settings.os == "Macos":
56+
self.cpp_info.frameworks.extend(["Foundation", "AVFoundation", "CoreVideo", "CoreMedia", "Accelerate"])
57+
elif self.settings.os == "Linux":
58+
self.cpp_info.system_libs.append("pthread")

scripts/release.sh

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
#!/bin/bash
2+
3+
# Release script for CameraCapture
4+
# This script validates version consistency, checks git history, and creates release tags
5+
# Usage: ./release.sh [-n|--dry-run]
6+
7+
set -e
8+
9+
# Color definitions for output
10+
RED='\033[0;31m'
11+
GREEN='\033[0;32m'
12+
YELLOW='\033[1;33m'
13+
BLUE='\033[0;34m'
14+
NC='\033[0m' # No Color
15+
16+
# Parse command line arguments
17+
DRY_RUN=false
18+
while [[ $# -gt 0 ]]; do
19+
case $1 in
20+
-n|--dry-run)
21+
DRY_RUN=true
22+
shift
23+
;;
24+
*)
25+
echo "Unknown option: $1"
26+
echo "Usage: $0 [-n|--dry-run]"
27+
exit 1
28+
;;
29+
esac
30+
done
31+
32+
# Get the project root directory (assuming script is in scripts/ folder)
33+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
34+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
35+
36+
# Change to project root
37+
cd "$PROJECT_ROOT"
38+
39+
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
40+
echo -e "${BLUE} CameraCapture Release Script${NC}"
41+
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
42+
echo ""
43+
44+
if [ "$DRY_RUN" = true ]; then
45+
echo -e "${YELLOW}⚠️ DRY-RUN MODE ENABLED (no actual changes will be made)${NC}"
46+
echo ""
47+
fi
48+
49+
# ============================================================================
50+
# Step 1: Extract and validate version from all sources
51+
# ============================================================================
52+
echo -e "${BLUE}Step 1: Extracting version from all sources...${NC}"
53+
echo ""
54+
55+
# Extract from ccap_config.h
56+
if [ ! -f "include/ccap_config.h" ]; then
57+
echo -e "${RED}❌ Error: include/ccap_config.h not found${NC}"
58+
exit 1
59+
fi
60+
61+
HEADER_MAJOR=$(grep "#define CCAP_VERSION_MAJOR" include/ccap_config.h | awk '{print $3}')
62+
HEADER_MINOR=$(grep "#define CCAP_VERSION_MINOR" include/ccap_config.h | awk '{print $3}')
63+
HEADER_PATCH=$(grep "#define CCAP_VERSION_PATCH" include/ccap_config.h | awk '{print $3}')
64+
HEADER_VERSION_STRING=$(grep "#define CCAP_VERSION_STRING" include/ccap_config.h | sed 's/.*"\([^"]*\)".*/\1/')
65+
66+
if [ -z "$HEADER_MAJOR" ] || [ -z "$HEADER_MINOR" ] || [ -z "$HEADER_PATCH" ]; then
67+
echo -e "${RED}❌ Error: Could not parse version macros from include/ccap_config.h${NC}"
68+
exit 1
69+
fi
70+
71+
HEADER_VERSION="${HEADER_MAJOR}.${HEADER_MINOR}.${HEADER_PATCH}"
72+
echo -e " Header (ccap_config.h): ${GREEN}$HEADER_VERSION${NC}"
73+
74+
# Validate header version consistency
75+
if [ "$HEADER_VERSION" != "$HEADER_VERSION_STRING" ]; then
76+
echo -e "${RED}❌ Error: Version mismatch in header file!${NC}"
77+
echo -e " Calculated: $HEADER_VERSION, String: $HEADER_VERSION_STRING"
78+
exit 1
79+
fi
80+
81+
# Extract from ccap.podspec
82+
if [ ! -f "ccap.podspec" ]; then
83+
echo -e "${RED}❌ Error: ccap.podspec not found${NC}"
84+
exit 1
85+
fi
86+
87+
PODSPEC_VERSION=$(grep '^ s.version' ccap.podspec | sed 's/.*"\([^"]*\)".*/\1/')
88+
if [ -z "$PODSPEC_VERSION" ]; then
89+
echo -e "${RED}❌ Error: Could not extract version from ccap.podspec${NC}"
90+
exit 1
91+
fi
92+
echo -e " Podspec (ccap.podspec): ${GREEN}$PODSPEC_VERSION${NC}"
93+
94+
# Extract from conanfile.py (optional file)
95+
if [ -f "conanfile.py" ]; then
96+
CONAN_VERSION=$(grep 'version = ' conanfile.py | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
97+
if [ -z "$CONAN_VERSION" ]; then
98+
echo -e "${RED}❌ Error: Could not extract version from conanfile.py${NC}"
99+
exit 1
100+
fi
101+
echo -e " Conan (conanfile.py): ${GREEN}$CONAN_VERSION${NC}"
102+
else
103+
echo -e " Conan (conanfile.py): ${YELLOW}(not found, skipping)${NC}"
104+
CONAN_VERSION=""
105+
fi
106+
107+
# Extract from BUILD_AND_INSTALL.md
108+
if [ ! -f "BUILD_AND_INSTALL.md" ]; then
109+
echo -e "${RED}❌ Error: BUILD_AND_INSTALL.md not found${NC}"
110+
exit 1
111+
fi
112+
113+
DOC_VERSION=$(grep 'Current version:' BUILD_AND_INSTALL.md | head -1 | sed 's/.*: \([^ ]*\).*/\1/')
114+
if [ -z "$DOC_VERSION" ]; then
115+
echo -e "${RED}❌ Error: Could not extract version from BUILD_AND_INSTALL.md${NC}"
116+
exit 1
117+
fi
118+
echo -e " Documentation (BUILD_AND_INSTALL.md): ${GREEN}$DOC_VERSION${NC}"
119+
120+
echo ""
121+
122+
# ============================================================================
123+
# Step 2: Validate version consistency across all files
124+
# ============================================================================
125+
echo -e "${BLUE}Step 2: Validating version consistency...${NC}"
126+
echo ""
127+
128+
VERSIONS=("$HEADER_VERSION" "$PODSPEC_VERSION" "$DOC_VERSION")
129+
# Only add conanfile version if it exists
130+
if [ -n "$CONAN_VERSION" ]; then
131+
VERSIONS+=("$CONAN_VERSION")
132+
fi
133+
134+
for version in "${VERSIONS[@]}"; do
135+
if [ "$version" != "$HEADER_VERSION" ]; then
136+
echo -e "${RED}❌ Version mismatch detected!${NC}"
137+
echo -e " Expected: $HEADER_VERSION, Found: $version"
138+
CONSISTENT=false
139+
fi
140+
done
141+
142+
if [ "$CONSISTENT" = false ]; then
143+
echo ""
144+
echo -e "${RED}❌ Version inconsistency detected across files!${NC}"
145+
echo -e " Please run: ./scripts/update_version.sh $HEADER_VERSION"
146+
exit 1
147+
fi
148+
149+
echo -e "${GREEN}✅ All versions are consistent: $HEADER_VERSION${NC}"
150+
echo ""
151+
152+
CURRENT_VERSION="$HEADER_VERSION"
153+
154+
# ============================================================================
155+
# Step 3: Check git repository status
156+
# ============================================================================
157+
echo -e "${BLUE}Step 3: Checking git repository status...${NC}"
158+
echo ""
159+
160+
# Check if we are in a git repository
161+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
162+
echo -e "${RED}❌ Error: Not in a git repository${NC}"
163+
exit 1
164+
fi
165+
166+
# Check for uncommitted changes
167+
if ! git diff-index --quiet HEAD --; then
168+
echo -e "${RED}❌ Error: Uncommitted changes detected!${NC}"
169+
echo -e " Please commit all changes before releasing"
170+
git status --short
171+
exit 1
172+
fi
173+
174+
echo -e "${GREEN}✅ Git repository is clean${NC}"
175+
echo ""
176+
177+
# ============================================================================
178+
# Step 4: Get all existing version tags from git history
179+
# ============================================================================
180+
echo -e "${BLUE}Step 4: Checking existing version tags...${NC}"
181+
echo ""
182+
183+
# Get all tags matching version pattern (v*.*.*, v*.*.*-alpha*, v*.*.*-beta*, v*.*.*-rc*)
184+
VERSION_TAGS=$(git tag -l | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | sort -V)
185+
186+
if [ -z "$VERSION_TAGS" ]; then
187+
echo -e "${YELLOW}ℹ️ No existing version tags found${NC}"
188+
LATEST_TAG="0.0.0"
189+
else
190+
echo -e " Existing tags:"
191+
echo "$VERSION_TAGS" | sed 's/^/ - /'
192+
LATEST_TAG=$(echo "$VERSION_TAGS" | tail -1 | sed 's/^v//')
193+
echo ""
194+
echo -e " Latest tag: ${GREEN}$LATEST_TAG${NC}"
195+
fi
196+
197+
echo ""
198+
199+
# ============================================================================
200+
# Step 5: Check if current version already exists
201+
# ============================================================================
202+
echo -e "${BLUE}Step 5: Checking if version already exists in git history...${NC}"
203+
echo ""
204+
205+
RELEASE_TAG="v$CURRENT_VERSION"
206+
207+
if git rev-parse "$RELEASE_TAG" >/dev/null 2>&1; then
208+
echo -e "${RED}❌ Error: Release tag already exists!${NC}"
209+
echo -e " Tag: $RELEASE_TAG"
210+
echo -e " Please update the version number in include/ccap_config.h"
211+
exit 1
212+
fi
213+
214+
echo -e "${GREEN}✅ Version $CURRENT_VERSION does not exist in git history${NC}"
215+
echo ""
216+
217+
# ============================================================================
218+
# Step 6: Compare current version with latest existing version
219+
# ============================================================================
220+
echo -e "${BLUE}Step 6: Comparing version with latest existing version...${NC}"
221+
echo ""
222+
223+
# Compare versions using semantic versioning rules
224+
compare_versions() {
225+
local v1=$1
226+
local v2=$2
227+
228+
# Convert versions to comparable format (e.g., 1.2.3 -> 001002003)
229+
local v1_parts=(${v1//./ })
230+
local v2_parts=(${v2//./ })
231+
232+
local v1_num=$(printf "%03d%03d%03d" ${v1_parts[0]} ${v1_parts[1]} ${v1_parts[2]})
233+
local v2_num=$(printf "%03d%03d%03d" ${v2_parts[0]} ${v2_parts[1]} ${v2_parts[2]})
234+
235+
if [ "$v1_num" -gt "$v2_num" ]; then
236+
echo "greater"
237+
elif [ "$v1_num" -eq "$v2_num" ]; then
238+
echo "equal"
239+
else
240+
echo "less"
241+
fi
242+
}
243+
244+
if [ "$LATEST_TAG" != "0.0.0" ]; then
245+
COMPARE=$(compare_versions "$CURRENT_VERSION" "$LATEST_TAG")
246+
247+
if [ "$COMPARE" = "equal" ]; then
248+
echo -e "${RED}❌ Error: Version is not higher than the latest release!${NC}"
249+
echo -e " Current: $CURRENT_VERSION, Latest: $LATEST_TAG"
250+
exit 1
251+
elif [ "$COMPARE" = "less" ]; then
252+
echo -e "${RED}❌ Error: Version must be higher than existing releases!${NC}"
253+
echo -e " Current: $CURRENT_VERSION, Latest: $LATEST_TAG"
254+
exit 1
255+
fi
256+
257+
echo -e " Latest version: $LATEST_TAG"
258+
echo -e " Current version: $CURRENT_VERSION"
259+
echo -e "${GREEN}✅ Version is higher than the latest release${NC}"
260+
else
261+
echo -e "${GREEN}✅ This is the first release (no previous versions found)${NC}"
262+
fi
263+
264+
echo ""
265+
266+
# ============================================================================
267+
# Step 7: Create and push release tag
268+
# ============================================================================
269+
echo -e "${BLUE}Step 7: Creating and pushing release tag...${NC}"
270+
echo ""
271+
272+
echo -e " Release tag: ${GREEN}$RELEASE_TAG${NC}"
273+
echo -e " Release version: ${GREEN}$CURRENT_VERSION${NC}"
274+
275+
if [ "$DRY_RUN" = true ]; then
276+
echo ""
277+
echo -e "${YELLOW}DRY-RUN: Skipping actual tag creation and push${NC}"
278+
echo ""
279+
echo -e "${GREEN}✅ Dry-run completed successfully!${NC}"
280+
echo ""
281+
echo -e "${BLUE}What would be executed:${NC}"
282+
echo -e " ${BLUE}git tag -a $RELEASE_TAG -m \"Release $CURRENT_VERSION\"${NC}"
283+
echo -e " ${BLUE}git push github $RELEASE_TAG${NC}"
284+
exit 0
285+
fi
286+
287+
# Create annotated tag
288+
if ! git tag -a "$RELEASE_TAG" -m "Release $CURRENT_VERSION"; then
289+
echo -e "${RED}❌ Error: Failed to create tag $RELEASE_TAG${NC}"
290+
exit 1
291+
fi
292+
293+
echo -e "${GREEN}✅ Tag created: $RELEASE_TAG${NC}"
294+
295+
# Push tag to remote
296+
if ! git push github "$RELEASE_TAG"; then
297+
echo -e "${RED}❌ Error: Failed to push tag to remote${NC}"
298+
echo -e " Cleaning up local tag..."
299+
git tag -d "$RELEASE_TAG"
300+
exit 1
301+
fi
302+
303+
echo -e "${GREEN}✅ Tag pushed to remote${NC}"
304+
echo ""
305+
306+
# ============================================================================
307+
# Success Summary
308+
# ============================================================================
309+
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
310+
echo -e "${GREEN}✅ Release completed successfully!${NC}"
311+
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
312+
echo ""
313+
echo -e " Release version: ${GREEN}$CURRENT_VERSION${NC}"
314+
echo -e " Release tag: ${GREEN}$RELEASE_TAG${NC}"
315+
echo ""
316+
echo -e "${BLUE}Next steps:${NC}"
317+
echo -e " 1. GitHub Actions will automatically build and create a release"
318+
echo -e " 2. Monitor the workflow at: https://github.com/wysaid/CameraCapture/actions"
319+
echo -e " 3. Verify the release at: https://github.com/wysaid/CameraCapture/releases/tag/$RELEASE_TAG"
320+
echo ""

0 commit comments

Comments
 (0)