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
10 changes: 10 additions & 0 deletions .github/package-check/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.13...3.31)
project(package_check CXX)

# Uses the SDK only through find_package, the way an app that installed it or got it from vcpkg or Conan does
find_package(countly CONFIG REQUIRED)
add_executable(app app.cpp)
target_link_libraries(app PRIVATE countly::countly)
if(EXPECT_COUNTLY_SQLITE)
target_compile_definitions(app PRIVATE EXPECT_COUNTLY_SQLITE)
endif()
30 changes: 30 additions & 0 deletions .github/package-check/app.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "countly.hpp"
#include <iostream>

#if defined(EXPECT_COUNTLY_SQLITE) && !defined(COUNTLY_USE_SQLITE)
#error "COUNTLY_USE_SQLITE did not reach the app through find_package"
#endif

int main() {
cly::Countly &countly = cly::Countly::getInstance();
countly.setHTTPClient([](bool use_post, const std::string &path, const std::string &data) {
(void)use_post;
(void)path;
(void)data;
return cly::HTTPResponse{true, nlohmann::json::object()};
});
#ifdef EXPECT_COUNTLY_SQLITE
countly.setDatabasePath("install_check.db");
#endif
countly.setDeviceID("install-check-device");
countly.start("install-check-app-key", "https://example.invalid", 443, false);

cly::Event event("install_check", 1);
event.addSegmentation("source", "installed package");
countly.addEvent(event);
const bool started = countly.checkEQSize() >= 0;
std::cout << event.serialize() << (started ? " recorded" : " not recorded: the SDK did not start") << std::endl;

countly.stop();
return started ? 0 : 1;
}
259 changes: 259 additions & 0 deletions .github/workflows/packaging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
name: Package Managers

on:
push:
branches: [master, staging]
paths:
- "CMakeLists.txt"
- "cmake/**"
- "include/**"
- "src/**"
- "packaging/**"
- ".github/package-check/**"
- ".github/workflows/packaging.yml"
pull_request:
branches: [master, staging]
paths:
- "CMakeLists.txt"
- "cmake/**"
- "include/**"
- "src/**"
- "packaging/**"
- ".github/package-check/**"
- ".github/workflows/packaging.yml"
workflow_dispatch:

# A new push to the same branch/PR cancels the still-running previous run.
concurrency:
group: packaging-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# ──────────────────────────────────────────────
# The vcpkg port and the Conan recipe carry the
# SDK version, so they cannot ship with an old one.
# ──────────────────────────────────────────────
versions:
name: package-versions
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Compare the package versions with COUNTLY_SDK_VERSION
run: |
version=$(sed -n 's/^#define COUNTLY_SDK_VERSION "\(.*\)"$/\1/p' include/countly/constants.hpp)
echo "SDK version: $version"
status=0
if ! grep -qF "\"version\": \"$version\"" packaging/vcpkg/ports/countly-sdk-cpp/vcpkg.json; then
echo "::error file=packaging/vcpkg/ports/countly-sdk-cpp/vcpkg.json::version is not $version"
status=1
fi
for file in packaging/conan/countly-sdk-cpp/config.yml packaging/conan/countly-sdk-cpp/all/conandata.yml; do
if ! grep -qxF " \"$version\":" "$file"; then
echo "::error file=$file::no entry for $version"
status=1
fi
done
exit $status

# ──────────────────────────────────────────────
# vcpkg: the port builds from an archive of this
# commit, then an app uses it through vcpkg's CMake
# toolchain, without and with the sqlite feature.
# Android only builds: its binaries cannot run here.
# ──────────────────────────────────────────────
vcpkg:
name: vcpkg-${{ matrix.triplet }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
triplet: x64-linux
run-app: true
- os: windows-2022
triplet: x64-windows
run-app: true
- os: macos-15
triplet: arm64-osx
run-app: true
- os: ubuntu-24.04
triplet: arm64-android
run-app: false
defaults:
run:
shell: bash
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Pack this commit like a release and point the port at it
run: |
work=$RUNNER_TEMP
if command -v cygpath > /dev/null; then
work=$(cygpath -m "$work")
fi
echo "WORK=$work" >> "$GITHUB_ENV"
echo "VCPKG_ROOT=$work/vcpkg" >> "$GITHUB_ENV"
echo "VCPKG_BINARY_SOURCES=clear;files,$work/vcpkg-cache,readwrite" >> "$GITHUB_ENV"
mkdir -p "$work/vcpkg-cache" "$work/ports"

# git archive leaves the submodules out, as GitHub's release archives do
git archive --format=tar.gz --prefix=countly-sdk-cpp/ -o "$work/countly-sdk-cpp.tar.gz" HEAD
cp -r packaging/vcpkg/ports/countly-sdk-cpp "$work/ports/"
portfile="$work/ports/countly-sdk-cpp/portfile.cmake"
# Windows runners check files out with CRLF line endings
ARCHIVE="$work/countly-sdk-cpp.tar.gz" perl -0pi -e 's/vcpkg_from_github\(.*?\r?\n\)\r?\n/vcpkg_extract_source_archive(SOURCE_PATH ARCHIVE "$ENV{ARCHIVE}")\n/s' "$portfile"
if grep -q "vcpkg_from_github" "$portfile" || ! grep -q "vcpkg_extract_source_archive" "$portfile"; then
echo "::error file=packaging/vcpkg/ports/countly-sdk-cpp/portfile.cmake::could not point the port at the archive"
exit 1
fi

- name: Restore the vcpkg binary cache
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/vcpkg-cache
key: vcpkg-${{ matrix.triplet }}-${{ github.run_id }}
restore-keys: vcpkg-${{ matrix.triplet }}-

- name: Point vcpkg at the Android NDK
if: contains(matrix.triplet, 'android')
run: echo "ANDROID_NDK_HOME=${ANDROID_NDK_LATEST_HOME:-$ANDROID_NDK_HOME}" >> "$GITHUB_ENV"

- name: Set up vcpkg
run: git clone --depth 1 https://github.com/microsoft/vcpkg "$VCPKG_ROOT"

- name: Bootstrap vcpkg (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: '& "$env:VCPKG_ROOT/bootstrap-vcpkg.bat" -disableMetrics'

- name: Bootstrap vcpkg (Linux and macOS)
if: runner.os != 'Windows'
run: '"$VCPKG_ROOT/bootstrap-vcpkg.sh" -disableMetrics'

- name: Install the port
run: '"$VCPKG_ROOT/vcpkg" install countly-sdk-cpp --overlay-ports="$WORK/ports" --triplet ${{ matrix.triplet }}'

- name: Build and run an app with the port
if: matrix.run-app
run: |
cmake -S .github/package-check -B "$WORK/app" -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} -DCMAKE_BUILD_TYPE=Release
cmake --build "$WORK/app" --config Release
if [ "$RUNNER_OS" = "Windows" ]; then
"$WORK/app/Release/app.exe"
else
"$WORK/app/app"
fi

- name: Install the port with the sqlite feature
run: '"$VCPKG_ROOT/vcpkg" install "countly-sdk-cpp[sqlite]" --recurse --overlay-ports="$WORK/ports" --triplet ${{ matrix.triplet }}'

- name: Build and run an app with the sqlite feature
if: matrix.run-app
run: |
cmake -S .github/package-check -B "$WORK/app-sqlite" -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} -DCMAKE_BUILD_TYPE=Release -DEXPECT_COUNTLY_SQLITE=ON
cmake --build "$WORK/app-sqlite" --config Release
if [ "$RUNNER_OS" = "Windows" ]; then
"$WORK/app-sqlite/Release/app.exe"
else
"$WORK/app-sqlite/app"
fi

# vcpkg features must be additive: turning on sqlite must not break an app that never sets a database path
- name: Build and run an app that sets no database path with the sqlite feature
if: matrix.run-app
run: |
cmake -S .github/package-check -B "$WORK/app-sqlite-no-path" -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} -DCMAKE_BUILD_TYPE=Release
cmake --build "$WORK/app-sqlite-no-path" --config Release
if [ "$RUNNER_OS" = "Windows" ]; then
"$WORK/app-sqlite-no-path/Release/app.exe"
else
"$WORK/app-sqlite-no-path/app"
fi

# ──────────────────────────────────────────────
# Conan: the recipe builds from an archive of this
# commit and its test_package runs, without and with
# SQLite and as shared libraries, like ConanCenter's
# own builds; an app then uses the SQLite package.
# ──────────────────────────────────────────────
conan:
name: conan-${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, windows-2022, macos-15]
defaults:
run:
shell: bash
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install Conan
run: |
pip install "conan>=2,<3"
conan profile detect --force

- name: Restore the Conan package cache
uses: actions/cache@v4
with:
path: ~/.conan2/p
key: conan-${{ matrix.os }}-${{ github.run_id }}
restore-keys: conan-${{ matrix.os }}-

- name: Pack this commit like a release and point the recipe at it
run: |
work=$RUNNER_TEMP
if command -v cygpath > /dev/null; then
work=$(cygpath -m "$work")
fi
version=$(sed -n 's/^#define COUNTLY_SDK_VERSION "\(.*\)"$/\1/p' include/countly/constants.hpp)
echo "WORK=$work" >> "$GITHUB_ENV"
echo "COUNTLY_VERSION=$version" >> "$GITHUB_ENV"

# git archive leaves the submodules out, as GitHub's release archives do
git archive --format=tar.gz --prefix=countly-sdk-cpp/ -o "$work/countly-sdk-cpp.tar.gz" HEAD
sha256=$(sha256sum "$work/countly-sdk-cpp.tar.gz" | cut -d ' ' -f 1)
cp -r packaging/conan/countly-sdk-cpp/all "$work/recipe"
printf 'sources:\n "%s":\n url: "file:///%s"\n sha256: "%s"\n' "$version" "${work#/}/countly-sdk-cpp.tar.gz" "$sha256" > "$work/recipe/conandata.yml"
cat "$work/recipe/conandata.yml"

- name: Create the package
run: conan create "$WORK/recipe" --version "$COUNTLY_VERSION" --build=missing

- name: Create the package with SQLite
run: conan create "$WORK/recipe" --version "$COUNTLY_VERSION" --build=missing -o "countly-sdk-cpp/*:with_sqlite=True"

- name: Create the package as shared libraries
run: conan create "$WORK/recipe" --version "$COUNTLY_VERSION" --build=missing -o "*:shared=True"

- name: Build and run an app with the SQLite package
run: |
conan install --requires="countly-sdk-cpp/$COUNTLY_VERSION" -o "countly-sdk-cpp/*:with_sqlite=True" -g CMakeDeps -g CMakeToolchain --output-folder="$WORK/app-deps"
cmake -S .github/package-check -B "$WORK/app" -DCMAKE_TOOLCHAIN_FILE="$WORK/app-deps/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DEXPECT_COUNTLY_SQLITE=ON
cmake --build "$WORK/app" --config Release
if [ "$RUNNER_OS" = "Windows" ]; then
"$WORK/app/Release/app.exe"
else
"$WORK/app/app"
fi

# Keeps the saved cache to built packages, without sources and build folders
- name: Trim the Conan cache
run: conan cache clean "*"
35 changes: 24 additions & 11 deletions .github/workflows/release_notice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,28 @@ on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
# To check the github context
- name: Dump Github context
# A manual run announces the latest release again
- name: Find the release to announce
env:
GITHUB_CONTEXT: ${{ toJSON(github) }}
run: echo "$GITHUB_CONTEXT"
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
run: |
if [ -z "$TAG" ]; then
TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq .tagName)
fi
{
echo "RELEASE_TAG=$TAG"
echo "RELEASE_URL=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json url --jq .url)"
echo "RELEASE_BODY<<COUNTLY_RELEASE_BODY_END"
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json body --jq .body
echo "COUNTLY_RELEASE_BODY_END"
} >> "$GITHUB_ENV"
- name: Send custom JSON data to Slack workflow
id: slack
uses: slackapi/slack-github-action@v1.23.0
Expand All @@ -20,10 +33,10 @@ jobs:
payload: |
{
"repository": "${{ github.repository }}",
"tag_name": "${{ github.event.release.tag_name }}",
"tag_name": "${{ env.RELEASE_TAG }}",
"actor": "${{ github.actor }}",
"body": ${{ toJSON(github.event.release.body) }},
"html_url": "${{ github.event.release.html_url }}"
"body": ${{ toJSON(env.RELEASE_BODY) }},
"html_url": "${{ env.RELEASE_URL }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_RELEASE }}
Expand All @@ -32,8 +45,8 @@ jobs:
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
nodetail: true
title: New ${{ github.repository }} version ${{ github.event.release.tag_name }} published by ${{ github.actor }}
title: New ${{ github.repository }} version ${{ env.RELEASE_TAG }} published by ${{ github.actor }}
description: |
Release URL: ${{ github.event.release.html_url }}
Click [here](https://github.com/Countly/countly-server/blob/master/CHANGELOG.md) to view the change log.
`${{ github.event.release.body }}`
Release URL: ${{ env.RELEASE_URL }}
Click [here](https://github.com/${{ github.repository }}/blob/master/CHANGELOG.md) to view the change log.
`${{ env.RELEASE_BODY }}`
4 changes: 2 additions & 2 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ jobs:
subject-path: countly-sdk-cpp-${{ steps.generate.outputs.version }}.tar.gz
sbom-path: ${{ steps.generate.outputs.sbom_file }}

# No --clobber: the Conan recipe pins this archive's checksum, so a released archive must never be replaced
- name: Attach to release
if: github.event_name == 'release'
run: |
gh release upload "${{ github.event.release.tag_name }}" \
"${{ steps.generate.outputs.sbom_file }}" \
"countly-sdk-cpp-${{ steps.generate.outputs.version }}.tar.gz" \
--clobber
"countly-sdk-cpp-${{ steps.generate.outputs.version }}.tar.gz"
env:
GH_TOKEN: ${{ github.token }}

Expand Down
Loading
Loading