diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..0817d818 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,161 @@ +name: Release + +on: + push: + branches: [main] + workflow_dispatch: + inputs: + version_type: + description: 'Version bump type' + required: true + default: 'auto' + type: choice + options: + - auto + - patch + - minor + - major + custom_version: + description: 'Custom version (optional, overrides version_type)' + required: false + type: string + +jobs: + release: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Determine version bump + id: version + run: | + # Get current version from CMakeLists.txt + CURRENT_VERSION=$(grep "project(c2pa-c VERSION" CMakeLists.txt | sed -n 's/.*VERSION \([0-9.]*\).*/\1/p') + echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + + # Determine bump type based on trigger + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + # Manual trigger + if [ -n "${{ github.event.inputs.custom_version }}" ]; then + NEW_VERSION="${{ github.event.inputs.custom_version }}" + BUMP="custom" + else + MANUAL_BUMP="${{ github.event.inputs.version_type }}" + if [ "$MANUAL_BUMP" = "auto" ]; then + # Auto-detect from recent commits + COMMITS=$(git log HEAD~5..HEAD --oneline) + if echo "$COMMITS" | grep -qE "^[a-f0-9]+ (feat!|BREAKING CHANGE)"; then + BUMP="major" + elif echo "$COMMITS" | grep -qE "^[a-f0-9]+ feat"; then + BUMP="minor" + elif echo "$COMMITS" | grep -qE "^[a-f0-9]+ (fix|chore|docs)"; then + BUMP="patch" + else + BUMP="patch" # Default for manual + fi + else + BUMP="$MANUAL_BUMP" + fi + fi + else + # Automatic trigger from push + LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + COMMITS=$(git log $LAST_TAG..HEAD --oneline) + + if echo "$COMMITS" | grep -qE "^[a-f0-9]+ (feat!|BREAKING CHANGE)"; then + BUMP="major" + elif echo "$COMMITS" | grep -qE "^[a-f0-9]+ feat"; then + BUMP="minor" + elif echo "$COMMITS" | grep -qE "^[a-f0-9]+ (fix|chore|docs)"; then + BUMP="patch" + else + echo "No version bump needed" + exit 0 + fi + fi + + # Calculate new version if not custom + if [ "$BUMP" != "custom" ]; then + IFS='.' read -r major minor patch <<< "$CURRENT_VERSION" + case $BUMP in + major) NEW_VERSION="$((major + 1)).0.0" ;; + minor) NEW_VERSION="$major.$((minor + 1)).0" ;; + patch) NEW_VERSION="$major.$minor.$((patch + 1))" ;; + esac + fi + + echo "bump_type=$BUMP" >> $GITHUB_OUTPUT + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "Version bump: $CURRENT_VERSION -> $NEW_VERSION ($BUMP)" + + - name: Update version in CMakeLists.txt + if: steps.version.outputs.new_version != '' + run: | + NEW_VERSION=${{ steps.version.outputs.new_version }} + sed -i "s/project(c2pa-c VERSION [0-9.]*)/project(c2pa-c VERSION $NEW_VERSION)/" CMakeLists.txt + echo "Updated version to $NEW_VERSION" + + - name: Install dependencies + if: steps.version.outputs.new_version != '' + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Run tests + if: steps.version.outputs.new_version != '' + run: | + echo "Running tests before release..." + make test # Debug build and test + make test-release # Release build and test + echo "✅ All tests passed!" + + - name: Commit version bump + if: steps.version.outputs.new_version != '' + run: | + NEW_VERSION=${{ steps.version.outputs.new_version }} + + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add CMakeLists.txt + git commit -m "chore(release): $NEW_VERSION [skip ci]" + git push + + - name: Create tag and release + if: steps.version.outputs.new_version != '' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + NEW_VERSION=${{ steps.version.outputs.new_version }} + + # Create and push tag + git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION" + git push origin "v$NEW_VERSION" + + # Generate release notes + LAST_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "") + if [ -n "$LAST_TAG" ]; then + COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges) + COMPARE_URL="https://github.com/${{ github.repository }}/compare/$LAST_TAG...v$NEW_VERSION" + else + COMMITS=$(git log --oneline --no-merges -10) + COMPARE_URL="https://github.com/${{ github.repository }}/commits/main" + fi + + # Create release + cat > release_notes.md << EOF + ## What's Changed + + $COMMITS + + **Full Changelog**: $COMPARE_URL + EOF + + gh release create "v$NEW_VERSION" \ + --title "Release v$NEW_VERSION" \ + --notes-file release_notes.md diff --git a/.github/workflows/update_c2pa.yml b/.github/workflows/update_c2pa.yml index f79d2030..9cca8ff7 100644 --- a/.github/workflows/update_c2pa.yml +++ b/.github/workflows/update_c2pa.yml @@ -18,6 +18,22 @@ jobs: run: | version="${{ github.event.inputs.c2pa_version }}" sed -i "s/set(C2PA_VERSION \".*\")/set(C2PA_VERSION \"${version}\")/" CMakeLists.txt + echo "Updated C2PA_VERSION to $version" + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Test with new c2pa-rs version + run: | + echo "Testing with c2pa-rs version ${{ github.event.inputs.c2pa_version }}..." + + # Test using our Makefile targets + make test # Debug build and test + make test-release # Release build and test + + echo "✅ All tests passed with c2pa-rs ${{ github.event.inputs.c2pa_version }}" - name: Create Pull Request uses: peter-evans/create-pull-request@v6 @@ -27,3 +43,7 @@ jobs: title: "Bump C2PA_VERSION to ${{ github.event.inputs.c2pa_version }}" body: | This PR updates C2PA_VERSION in CMakeLists.txt to ${{ github.event.inputs.c2pa_version }}. + + ✅ **Tests Status**: All tests (debug and release builds) have passed with the new c2pa-rs version. + + The new version should be compatible and ready for integration. diff --git a/Makefile b/Makefile index 04e674de..a16d7aff 100644 --- a/Makefile +++ b/Makefile @@ -22,18 +22,26 @@ release: cmake: release # Test targets + test: debug cd $(DEBUG_BUILD_DIR) && ctest --output-on-failure test-release: release cd $(RELEASE_BUILD_DIR) && ctest --output-on-failure -# Demo targets -demo: release +demo: debug + cmake --build $(DEBUG_BUILD_DIR) --target demo + $(DEBUG_BUILD_DIR)/examples/demo + +demo-release: release cmake --build $(RELEASE_BUILD_DIR) --target demo $(RELEASE_BUILD_DIR)/examples/demo -training: release +training: debug + cmake --build $(DEBUG_BUILD_DIR) --target training + $(DEBUG_BUILD_DIR)/examples/training + +training-release: release cmake --build $(RELEASE_BUILD_DIR) --target training $(RELEASE_BUILD_DIR)/examples/training @@ -42,5 +50,10 @@ examples: training demo clean: rm -rf $(BUILD_DIR) -.PHONY: all debug release cmake test test-release demo training examples clean +clean-debug: + rm -rf $(DEBUG_BUILD_DIR) + +clean-release: + rm -rf $(RELEASE_BUILD_DIR) +.PHONY: all debug release cmake test test-release demo training examples clean diff --git a/README.md b/README.md index 33b0080c..dbc94133 100644 --- a/README.md +++ b/README.md @@ -61,18 +61,21 @@ make release ``` The Makefile has a number of other targets; for example: -- `unit-tests` to run C++ unit tests -- `examples` to build and run the C++ examples. -- `all` to run everything. +- `debug` to build in debug mode +- `release` to build in optimized release mode +- `test` to run all tests (debug build) +- `test-release` to run all tests (release build) +- `examples` to build and run the C++ examples +- `all` to run tests and examples -Results are saved in the `build` directory. +Results are saved in the `build/debug` and `build/release` directories. ### Testing Build the [unit tests](https://github.com/contentauth/c2pa-c/tree/main/tests) by entering this `make` command: ``` -make unit-test +make test ``` ## License diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cd0eba10..e97baa32 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,22 +19,6 @@ function(setup_c2pa_runtime_deps target_name) COMMAND ${CMAKE_COMMAND} -E echo "Copied ${C2PA_C_LIB} to $" COMMENT "Copying c2pa_c library to ${target_name} directory" ) - - # On Windows, copy all DLLs from the prebuilt lib directory - if(WIN32) - add_custom_command(TARGET ${target_name} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo "=== Windows DLL Debug Info for ${target_name} ===" - COMMAND ${CMAKE_COMMAND} -E echo "Listing prebuilt lib directory contents:" - COMMAND ${CMAKE_COMMAND} -E echo "Skipping directory listing due to Windows path issues" - COMMAND ${CMAKE_COMMAND} -E echo "Target directory contents:" - COMMAND cmd /c "dir \"$\"" || echo "Failed to list target directory" - COMMENT "Windows DLL debugging for ${target_name}" - ) - else() - add_custom_command(TARGET ${target_name} POST_BUILD - COMMAND ls -la $ || echo "Failed to list directory" - ) - endif() endif() # On Linux, set RPATH to look in the executable's directory @@ -74,17 +58,7 @@ setup_c2pa_runtime_deps(c2pa_c_tests) include(GoogleTest) -# Add debug commands to check what's happening on Linux -if(UNIX AND NOT APPLE) - add_test(NAME debug_rpath_info - COMMAND bash -c "echo '=== RPATH Debug Info ===' && echo 'Working dir:' && pwd && echo 'Library files in tests dir:' && ls -la ${CMAKE_BINARY_DIR}/tests/ && echo 'RPATH of c2pa_c_tests:' && readelf -d ${CMAKE_BINARY_DIR}/tests/c2pa_c_tests | grep -E '(RPATH|RUNPATH)' && echo 'RPATH of ctest:' && readelf -d ${CMAKE_BINARY_DIR}/tests/ctest | grep -E '(RPATH|RUNPATH)' && echo 'ldd output for c2pa_c_tests:' && ldd ${CMAKE_BINARY_DIR}/tests/c2pa_c_tests" - ) - - add_test(NAME debug_library_location - COMMAND bash -c "echo '=== Library Location Debug ===' && echo 'Current dir:' && pwd && echo 'Contents of build/debug:' && ls -la ${CMAKE_BINARY_DIR}/ && echo 'Contents of _deps:' && ls -la ${CMAKE_BINARY_DIR}/_deps/ && echo 'Contents of prebuilt lib:' && ls -la ${CMAKE_BINARY_DIR}/_deps/c2pa_prebuilt-src/lib/ && echo 'Does the relative path exist from tests dir?' && ls -la ${CMAKE_BINARY_DIR}/tests/../_deps/c2pa_prebuilt-src/lib/" - ) -endif() - +# C++ test registration # For better reliability, especially on Linux, manually add tests instead of auto-discovery # This avoids the working directory and library path issues during discovery if(WIN32) diff --git a/tests/test.c b/tests/test.c index b2299175..687d8d4a 100644 --- a/tests/test.c +++ b/tests/test.c @@ -20,6 +20,14 @@ int main(void) { + // Clean up any existing test output files + remove("build/tmp/earth1.jpg"); + remove("build/tmp/earth2.jpg"); + remove("build/tmp/earth3.jpg"); + remove("build/tmp/earth1.pem"); + remove("build/tmp/archive.zip"); + remove("build/thumb_c.jpg"); + char *version = c2pa_version(); assert_contains("version", version, "c2pa-c-ffi/0."); @@ -71,12 +79,10 @@ int main(void) // create a sign_info struct (using positional initialization to avoid designated initializers) C2paSignerInfo sign_info = {"es256", certs, private_key, "http://timestamp.digicert.com"}; - // Remove the file if it exists - remove("build/tmp/earth.jpg"); - result = c2pa_sign_file("tests/fixtures/C.jpg", "build/tmp/earth.jpg", manifest, &sign_info, "tests/fixtures"); + result = c2pa_sign_file("tests/fixtures/C.jpg", "build/tmp/earth1.jpg", manifest, &sign_info, "tests/fixtures"); assert_not_null("c2pa_sign_file_ok", result); - remove("build/tmp/earth2.jpg"); + result = c2pa_sign_file("tests/fixtures/foo.jpg", "build/tmp/earth2.jpg", manifest, &sign_info, "tests/fixtures"); assert_null("c2pa_sign_file_not_found", result, "FileNotFound"); @@ -101,8 +107,7 @@ int main(void) assert_not_null("c2pa_signer_create", signer); C2paStream *source = open_file_stream("tests/fixtures/C.jpg", "rb"); - remove("build/tmp/earth4.jpg"); - C2paStream *dest = open_file_stream("build/tmp/earth4.jpg", "wb"); + C2paStream *dest = open_file_stream("build/tmp/earth3.jpg", "wb"); const unsigned char *manifest_bytes = NULL; // todo: test passing NULL instead of a pointer int result2 = c2pa_builder_sign(builder2, "image/jpeg", source, dest, signer, &manifest_bytes);