spec: fix openSUSE BuildRequires for qt6-core5compat and add runtime … #200
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# GitHub Action to CI build SocNetV for all 3 major OSes | |
# Triggered only when the commit message contains [gha] or [ci] | |
name: Build SocNetV (CI) 🚀 | |
on: | |
push: | |
branches: | |
- develop | |
env: | |
APP_NAME: "SocNetV" | |
UNIXNAME: "socnetv" | |
SOCNETV_VERSION: "3.2" # TODO - READ FROM FILE | |
VERSION: "3.2" # WILL BE UPDATED DYNAMICALLY BELOW | |
QMAKE_PROJECT: "socnetv.pro" | |
PUBLISHER: "Dimitris Kalamaras" | |
QT_MODULES: "qtwebsockets qtimageformats qt5compat qtcharts qtdatavis3d qtwebview qt3d" | |
QMAKE_CONFIG: release ## debug # Never use debug. Windows builds will break. | |
CMAKE_CONFIG: Release ## Debug | |
CORES: 16 | |
MAC_ARTIFACT: "" | |
LINUX_ARTIFACT: "" | |
APPDIR_PREFIX: "/usr" | |
WINDOWS_ARTIFACT: "" | |
UPLOAD_URL: '' | |
jobs: | |
ci_build: | |
permissions: | |
contents: write # Required to upload release assets | |
strategy: | |
fail-fast: false | |
matrix: | |
os: [ubuntu-20.04, ubuntu-latest, macos-latest, windows-2019] | |
# NOTE: | |
# - We will CI build only for Qt6 LTS releases, see: https://doc.qt.io/qt-6/qt-releases.html | |
# - For the Qt Versions supported by aqtinstall, see: https://ddalcino.github.io/aqt-list-server/ | |
qt-version: ['6.5.3', '6.8.0'] | |
# exclude: | |
# - os: ubuntu-latest | |
# qt-version: '6.6.3' | |
# - os: windows-2019 | |
# qt-version: '6.6.3' | |
# - os: macos-latest | |
# qt-version: '6.6.3' | |
# include: | |
# - os: macos-latest | |
# qt-version: '6.6.3' | |
# # Snapcraft | |
# - os: ubuntu-20.04 | |
# qt-version: '6.5.3' | |
runs-on: ${{ matrix.os }} | |
if: contains(github.event.head_commit.message, '[ci]') || contains(github.event.head_commit.message, '[gha]') | |
steps: | |
- name: 🤖 Job information, on branch ${{ github.ref }} | |
run: | | |
echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event, by actor ${{ github.actor }}." | |
echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" | |
echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." | |
- name: 📂 Check out repository ${{ github.repository }} | |
uses: actions/checkout@v4 | |
- name: 💡 List files cloned from the ${{ github.repository }} | |
run: | | |
ls ${{ github.workspace }} | |
echo "💡 The ${{ github.repository }} repository has been cloned to the runner." | |
echo "🖥️ The workflow is now ready to test your code on the runner." | |
- name: 💡 Set version dynamically | |
shell: bash | |
id: set_version | |
run: | | |
# Check if this is a tagged commit | |
if [ -n "${GITHUB_REF}" ] && [[ "${GITHUB_REF}" == refs/tags/* ]]; then | |
VERSION=${GITHUB_REF#refs/tags/} # Extract tag name | |
else | |
LAST_COMMIT_SHORT=$(git rev-parse --short HEAD) | |
VERSION="${SOCNETV_VERSION}-${LAST_COMMIT_SHORT}" # Use custom versioning for non-tagged commits | |
fi | |
# Export VERSION as an environment variable for subsequent steps | |
echo "VERSION=${VERSION}" >> $GITHUB_ENV | |
- name: Determined build version ${{ env.VERSION }} | |
run: echo "VERSION is set to ${{ env.VERSION }}" | |
- name: Check Rate Limit | |
uses: actions/github-script@v6 | |
id: get_ratelimit | |
with: | |
script: | | |
const { data: rateLimit } = await github.rest.rateLimit.get(); | |
console.log(rateLimit); | |
core.setOutput("rate_limit", rateLimit); | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Use script to get continuous release Upload URL | |
id: get_release | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const { data: releases } = await github.rest.repos.listReleases({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
}); | |
const release = releases.find(r => r.tag_name === "continuous"); | |
if (!release) { | |
console.log("Continuous release not found. Exiting gracefully."); | |
core.setOutput("upload_url", ""); | |
} else { | |
core.setOutput("upload_url", release.upload_url); | |
} | |
result-encoding: string | |
github-token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Fetch 'continuous' release upload URL | |
shell: bash | |
id: fetch_release | |
run: | | |
echo "steps.get_ratelimit.outputs.rate_limit = ${{ steps.get_ratelimit.outputs.rate_limit }}" | |
echo "steps.get_release.outputs.upload_url = ${{ steps.get_release.outputs.upload_url }}" | |
if [ -z "${{ steps.get_release.outputs.upload_url }}" ]; then | |
echo "No continuous release found in get_release step." | |
fi | |
RELEASE_INFO=$(gh api -H "Accept: application/vnd.github+json" https://api.github.com/repos/${{ github.repository }}/releases/tags/continuous) | |
UPLOAD_URL=$(echo "$RELEASE_INFO" | jq -r '.upload_url' | sed 's/{?name,label}//') | |
echo "UPLOAD_URL=${UPLOAD_URL}" >> $GITHUB_ENV | |
echo "UPLOAD_URL=${UPLOAD_URL}" | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: 🗑️ Delete old assets from 'continuous' release (only once, from ubuntu) | |
if: matrix.os == 'ubuntu-latest' && matrix.qt-version == '6.8.0' | |
run: | | |
echo "🔍 Fetching existing assets from the 'continuous' release..." | |
ASSETS=$(gh release view continuous --json assets -q '.assets[].name') | |
if [[ -z "$ASSETS" ]]; then | |
echo "✅ No previous assets found in 'continuous' release." | |
else | |
echo "🗑️ Deleting old assets..." | |
for ASSET in $ASSETS; do | |
echo "❌ Removing $ASSET..." | |
gh release delete-asset continuous "$ASSET" --yes | |
done | |
echo "✅ Old assets deleted." | |
fi | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
# | |
# Install dependencies (build tools, cmake, etc) | |
# | |
- if: contains( matrix.os, 'windows') | |
name: 🪟 Prepare for buiilding on ${{matrix.os}} | |
run: | | |
echo '⚙️ Install dependencies for building....' | |
# DONT NEED IT. FOR DEBUG ONLY | |
# pip install aqtinstall | |
# aqt list-qt windows desktop | |
# aqt list-qt windows desktop --arch ${{ matrix.qt-version }} | |
# aqt list-qt windows desktop --modules ${{ matrix.qt-version }} win64_mingw | |
- if: contains( matrix.os, 'ubuntu') | |
name: 🐧 Prepare for building on ${{matrix.os}} | |
run: | | |
echo '⚙️ Install dependencies for building....' | |
sudo apt install -y build-essential libssl-dev cmake ninja-build \ | |
libxkbcommon-x11-dev libxcb-cursor-dev zlib1g-dev libcups2-dev libvulkan-dev \ | |
desktop-file-utils patchelf libglu1-mesa-dev libfontconfig1 libfreetype6 libx11-dev libxext-dev \ | |
libxrandr-dev libxrender-dev libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libfuse2 | |
# DONT NEED IT. FOR DEBUG ONLY | |
# pip install aqtinstall | |
# aqt list-qt linux desktop --long-modules ${{ matrix.qt-version }} win64_mingw | |
- if: contains( matrix.os, 'macos') | |
name: 🍎 Prepare for building on ${{matrix.os}} | |
run: | | |
echo '⚙️ Install dependencies for building....' | |
ls | |
# DONT NEED IT. FOR DEBUG ONLY | |
# pip install aqtinstall | |
# aqt list-qt mac desktop --modules ${{ matrix.qt-version }} | |
# | |
# Install Qt (using https://github.com/jurplel/install-qt-action) | |
# | |
- if: contains( matrix.os, 'windows') | |
name: Make sure MSVC is found | |
uses: ilammy/msvc-dev-cmd@v1 | |
- if: contains( matrix.os, 'windows') && startsWith( matrix.qt-version, '6.' ) | |
name: Install Qt ${{ matrix.qt-version }} on ${{ matrix.os }} | |
uses: jurplel/install-qt-action@v4 | |
with: | |
aqtversion: '==3.1.*' # Use the default aqtinstall version | |
version: ${{ matrix.qt-version }} # Qt version to install | |
# arch: win64_mingw | |
# NOTE: We build with default arch: | |
# win64_msvc2019_64 if Qt < 6.8 | |
# win64_msvc2022_64 if Qt >= 6.8 | |
# see https://github.com/jurplel/install-qt-action | |
modules: ${{env.QT_MODULES}} | |
cache: true | |
- if: contains( matrix.os, 'ubuntu') && startsWith( matrix.qt-version, '6.' ) | |
name: Install Qt 6 on ${{ matrix.os }} | |
uses: jurplel/install-qt-action@v4 | |
with: | |
aqtversion: '==3.1.*' # Use the default aqtinstall version | |
version: ${{ matrix.qt-version }} # Qt version to install | |
modules: ${{env.QT_MODULES}} | |
cache: true | |
- if: contains( matrix.os, 'macos') && startsWith( matrix.qt-version, '6.' ) | |
name: Install Qt 6 on macOS | |
uses: jurplel/install-qt-action@v4 | |
with: | |
aqtversion: '==3.1.*' # Use the default aqtinstall version | |
version: ${{ matrix.qt-version }} | |
modules: ${{env.QT_MODULES}} | |
cache: true | |
# | |
# Build SocNetV | |
# | |
# Test building with qmake and Qt 6.5 | |
- if: matrix.os == 'ubuntu-20.04' && matrix.qt-version == '6.5.3' | |
name: Build ${{ env.VERSION }} for ${{matrix.os}} with Qt${{matrix.qt-version}} using qmake | |
run: | | |
echo "🔎 Check openssl version:" | |
echo `openssl version` | |
echo "🔎 Check output of 'which qmake6':" | |
which qmake6 | |
echo "🔎 Check qmake6 version:" | |
qmake6 -v | |
echo "🔧 Running qmake on ubuntu 22.04 with ${{env.QMAKE_CONFIG}}..." | |
qmake6 CONFIG+=${{env.QMAKE_CONFIG}} | |
echo "🚧 🛠️ Compiling for linux with make -j${{env.CORES}}. Please wait..." | |
make -j${{env.CORES}} | |
echo "👉 Building finished. Listing current directory with find for verification:" | |
find . | |
# Test building with cmake and all other versions of Qt | |
- if: matrix.os == 'ubuntu-20.04' && matrix.qt-version != '6.5.3' | |
name: Build ${{ env.VERSION }} for ${{matrix.os}} with Qt${{matrix.qt-version}} using cmake | |
run: | | |
echo "🔎 Check openssl version:" | |
echo `openssl version` | |
echo "💡 Checking current directory..." | |
pwd | |
echo "💡 List current directory..." | |
ls | |
echo "💡 Deleting old build subdirectory..." | |
rm -rf build | |
echo "🔧 Configuring project using 'cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}}' ..." | |
cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}} | |
echo "🔎 Verifying ./build directory (before compiling)..." | |
if [[ -d "./build" ]]; then | |
echo "🎉 ./build directory created! Contents:" | |
ls -lh ./build/ | |
else | |
echo "❌ Error! ./build directory was not created!" | |
exit 1 | |
fi | |
echo "🚧 Compiling the project..." | |
cmake --build build -j$(nproc) | |
echo "🔎 Entering build directory..." | |
cd build | |
ls -lh . | |
echo "🔎 Search for built executable ./${{env.UNIXNAME}}*..." | |
if [[ -f "./${{env.UNIXNAME}}" ]]; then | |
echo "🎉 executable found!" | |
ls -ls "${{env.UNIXNAME}}" | |
else | |
echo "❌ Error! ./build directory was not created!" | |
exit 1 | |
fi | |
# We build appImage on Ubuntu 20.04 and Qt 6.8 (latest LTS) | |
- if: contains( matrix.os, 'ubuntu-20.04') && matrix.qt-version == '6.8.0' | |
name: Create AppImage ${{ env.VERSION }} for ${{matrix.os}} with Qt${{matrix.qt-version}} | |
run: | | |
echo "💡 Checking current directory..." | |
pwd | |
echo "🔎 Check where we are..." | |
if [[ -d "./build" ]]; then | |
echo "We are outside of ./build directory! Entering..." | |
cd ./build/ | |
fi | |
echo "💡 List current directory (./build)..." | |
ls | |
echo "🔧 Installing the application into a new 'AppDir' directory..." | |
make install DESTDIR=AppDir | |
if [[ -d "./AppDir" ]]; then | |
echo "🎉 SocNetv Installed in AppDir successfully!" | |
else | |
echo "❌ Error: AppDir was not created!" | |
exit 1 | |
fi | |
echo "🔧 Installing linuxdeployqt..." | |
wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage | |
chmod a+x linuxdeployqt-continuous-x86_64.AppImage | |
# NOTE: linuxdeployqt supports up to Ubuntu Focal Fossa | |
echo "🚀 Creating the AppImage using linuxdeployqt..." | |
./linuxdeployqt-continuous-x86_64.AppImage AppDir/${{env.APPDIR_PREFIX}}/share/applications/*.desktop \ | |
-appimage -extra-plugins=iconengines,imageformats | |
ARTIFACT_FN="${{env.APP_NAME}}-${{env.VERSION}}-$(uname -i).AppImage" | |
if [[ -f ${ARTIFACT_FN} ]]; then | |
echo "🎉 AppImage created! Listing files in current directory..." | |
ls -lh ./*.AppImage | |
echo "...Exporting LINUX_ARTIFACT=${ARTIFACT_FN}" | |
echo "LINUX_ARTIFACT=${ARTIFACT_FN}" >> $GITHUB_ENV | |
else | |
echo "❌ AppImage creation failed!" | |
exit 1 | |
fi | |
- if: contains( matrix.os, 'ubuntu-20.04') && matrix.qt-version == '6.8.0' && env.LINUX_ARTIFACT != '' | |
name: 📤 Upload ${{matrix.os}} build artifacts of ${{env.APP_NAME}} ${{ env.VERSION }} to GitHub ${{ env.UPLOAD_URL }} | |
run: | | |
echo "🔍 Verifying artifact: ${{ env.LINUX_ARTIFACT }}" | |
pwd | |
ls build | |
if [ ! -f "./build/${{ env.LINUX_ARTIFACT }}" ]; then | |
echo "❌ Error: Artifact not found!" | |
exit 1 | |
fi | |
echo "📤 Uploading artifact to GitHub release..." | |
gh release upload continuous "./build/${{ env.LINUX_ARTIFACT }}" --repo "${{ github.repository }}" \ | |
--clobber | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
# - if: contains( matrix.os, 'ubuntu-20.04') && matrix.qt-version == '6.8.0' && env.LINUX_ARTIFACT != '' | |
# name: Upload ${{matrix.os}} build artifacts of ${{env.APP_NAME}} ${{ env.VERSION }} to GitHub ${{ env.UPLOAD_URL }} | |
# uses: actions/upload-release-asset@v1 | |
# with: | |
# upload_url: ${{ env.UPLOAD_URL }} | |
# asset_path: ./${{ env.LINUX_ARTIFACT }} | |
# asset_name: "${{ env.LINUX_ARTIFACT }}" | |
# asset_content_type: "application/octet-stream" | |
# env: | |
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- if: contains( matrix.os, 'ubuntu-latest') | |
name: Build ${{ env.VERSION }} for ${{matrix.os}} with Qt ${{matrix.qt-version}} using cmake | |
run: | | |
echo "🔎 Check openssl version:" | |
echo `openssl version` | |
echo "💡 Checking current directory..." | |
pwd | |
echo "💡 List current directory..." | |
ls | |
echo "💡 Deleting old build subdirectory..." | |
rm -rf build | |
echo "🔧 Configuring project using 'cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}}' ..." | |
cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}} | |
echo "🔎 Verifying ./build directory (before compiling)..." | |
if [[ -d "./build" ]]; then | |
echo "🎉 ./build directory created! Contents:" | |
ls -lh ./build/ | |
else | |
echo "❌ Error! ./build directory was not created!" | |
exit 1 | |
fi | |
echo "🚧 Compiling the project..." | |
cmake --build build -j$(nproc) | |
echo "🔎 Entering build directory..." | |
cd build | |
ls -lh . | |
echo "🔎 Search for built executable ./${{env.UNIXNAME}}*..." | |
if [[ -f "./${{env.UNIXNAME}}" ]]; then | |
echo "🎉 executable found!" | |
ls -ls "${{env.UNIXNAME}}" | |
else | |
echo "❌ Error! ./build directory was not created!" | |
exit 1 | |
fi | |
# BUILD FOR MACOS | |
- if: contains( matrix.os, 'macos') && matrix.qt-version == '6.5.3' | |
name: Build ${{env.APP_NAME}} ${{ env.VERSION }} for ${{matrix.os}} with Qt ${{matrix.qt-version}} using qmake | |
run: | | |
echo "🍎 Preparing macOS build..." | |
echo "Building version: ${{env.VERSION}}" | |
# Ensure Qt is installed and in PATH | |
# export PATH="$(brew --prefix qt)/bin:$PATH" | |
which qmake | |
echo "🔧 Running 'qmake CONFIG+=${{env.QMAKE_CONFIG}} ${{env.QMAKE_PROJECT}}' to configure on macos..." | |
qmake CONFIG+=${{env.QMAKE_CONFIG}} ${{env.QMAKE_PROJECT}} | |
echo "🚧 🛠️ Compiling for macos with make. Please wait..." | |
make | |
echo "👉 Building finished! Searching for built ${{matrix.os}} bundle (DIRECTORY!)./${{env.APP_NAME}}.app ..." | |
if [[ -d "./${{env.APP_NAME}}.app" ]]; then | |
echo "🎉 ${{matrix.os}} bundle created! Bundle contents:" | |
find "${{env.APP_NAME}}.app" | |
else | |
echo "❌ Error! ${{matrix.os}} bundle not found !" | |
exit 1 | |
fi | |
# Verify the binary with lipo | |
echo "🔎 Verifying architectures in the built binary..." | |
if [[ -f "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" ]]; then | |
lipo -info "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" | |
else | |
echo "❌ Error: Binary file not found!" | |
exit 1 | |
fi | |
echo "🔧 Removing items we do not deploy from project dir ..." | |
rm -rf moc obj qrc | |
# Run macdeployqt to bundle the app | |
echo "🚀 Running macdeployqt to create macOS bundle..." | |
macdeployqt "${{env.APP_NAME}}.app" -dmg -verbose=3 || { | |
echo "Error: macdeployqt failed." | |
exit 1 | |
} | |
# Verify the bundled libraries in the binary | |
echo "🔎 Verify the bundled libraries in the built binary ..." | |
if [[ -f "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" ]]; then | |
otool -L "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" | |
else | |
echo "❌ Error: Binary file not found!" | |
exit 1 | |
fi | |
# Rename DMG file | |
if [[ -f ${{env.APP_NAME}}.dmg ]]; then | |
DMG_NAME="${{env.APP_NAME}}-${{env.VERSION}}.dmg" | |
mv "${{env.APP_NAME}}.dmg" "${DMG_NAME}" | |
echo "🎉 Build and packaging complete. Final DMG: ${DMG_NAME}" | |
ls -lh *.dmg | |
echo "Artifact created! Exporting MAC_ARTIFACT=${DMG_NAME}" | |
echo "MAC_ARTIFACT=${DMG_NAME}" >> $GITHUB_ENV | |
else | |
echo "Error: DMG creation failed. No DMG file found. Skipping upload." | |
exit 1 | |
fi | |
- if: contains( matrix.os, 'macos') && matrix.qt-version != '6.5.3' | |
name: Build ${{env.APP_NAME}} ${{ env.VERSION }} for ${{matrix.os}} with Qt ${{matrix.qt-version}} using cmake | |
timeout-minutes: 360 # 6 hours maximum | |
run: | | |
echo "🍎 Preparing macOS build..." | |
echo "🔎 Check openssl version:" | |
echo `openssl version` | |
echo "💡 Checking current directory..." | |
pwd | |
echo "💡 List current directory..." | |
ls | |
echo "💡 Deleting old build subdirectory..." | |
rm -rf build | |
echo "🔧 Configuring project using 'cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}}' ..." | |
cmake -S . -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_CONFIG}} -DCMAKE_INSTALL_PREFIX=${{env.APPDIR_PREFIX}} | |
echo "🔎 Verifying ./build directory (before compiling)..." | |
if [[ -d "./build" ]]; then | |
echo "🎉 ./build directory created! Contents:" | |
ls -lh ./build/ | |
else | |
echo "❌ Error! ./build directory was not created!" | |
exit 1 | |
fi | |
echo "🚧 Compiling the project..." | |
cmake --build build -j$(sysctl -n hw.ncpu) | |
echo "🔎 Entering build directory..." | |
cd build | |
ls -lh . | |
echo "🔎 Search for built ${{matrix.os}} bundle (DIRECTORY!)./${{env.APP_NAME}}.app ..." | |
if [[ -d "./${{env.APP_NAME}}.app" ]]; then | |
echo "🎉 ${{matrix.os}} bundle created! Bundle contents:" | |
find "${{env.APP_NAME}}.app" | |
else | |
echo "❌ Error! ${{matrix.os}} bundle not found !" | |
exit 1 | |
fi | |
# Verify the binary with lipo | |
echo "🔎 Verifying architectures in the ${{matrix.os}} bundle..." | |
if [[ -f "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" ]]; then | |
lipo -info "${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}}" | |
else | |
echo "❌ Error: ${{env.APP_NAME}}.app/Contents/MacOS/${{env.APP_NAME}} file not found!" | |
exit 1 | |
fi | |
echo "🔑 Import macOS Developer Certificate" | |
echo "${{ secrets.MACOS_CERTIFICATE }}" | base64 --decode > certificate.p12 | |
security create-keychain -p "" build.keychain | |
security default-keychain -s build.keychain | |
security unlock-keychain -p "" build.keychain | |
security import certificate.p12 -k build.keychain -P "${{ secrets.MACOS_CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign | |
security set-key-partition-list -S apple-tool:,apple: -k "" build.keychain | |
rm -f certificate.p12 | |
echo "🛠️ Store Apple ID Credentials for Notarization" | |
xcrun notarytool store-credentials "AC_PASSWORD" \ | |
--apple-id "${{ secrets.AC_APPLE_ID }}" \ | |
--team-id "${{ secrets.AC_TEAM_ID }}" \ | |
--password "${{ secrets.AC_PASSWORD }}" | |
echo "🔧 Checking bundle structure before packaging..." | |
# Remove any PkgInfo file in the root of the app bundle | |
if [[ -f "${{env.APP_NAME}}.app/PkgInfo" ]]; then | |
echo "⚠️ Found PkgInfo in root directory - removing it" | |
rm "${{env.APP_NAME}}.app/PkgInfo" | |
fi | |
# Ensure PkgInfo exists in the Contents directory | |
if [[ ! -f "${{env.APP_NAME}}.app/Contents/PkgInfo" ]]; then | |
echo "Creating PkgInfo in Contents directory" | |
echo "APPL????" > "${{env.APP_NAME}}.app/Contents/PkgInfo" | |
fi | |
# Clear extended attributes that could interfere with signing | |
find "${{env.APP_NAME}}.app" -type f -exec xattr -c {} \; | |
# First run macdeployqt WITHOUT creating DMG yet | |
echo "🚀 Running macdeployqt to bundle required libraries..." | |
macdeployqt "${{env.APP_NAME}}.app" -verbose=3 || { | |
echo "Error: macdeployqt failed." | |
exit 1 | |
} | |
# Now sign the .app bundle AFTER macdeployqt has added all dependencies | |
echo "🔏 Sign the application bundle" | |
codesign --deep --force --verbose \ | |
--options runtime \ | |
--entitlements ../scripts/entitlements.plist \ | |
--sign "Developer ID Application: Dimitris Kalamaras (${{ secrets.AC_TEAM_ID }})" \ | |
"${{env.APP_NAME}}.app" | |
# Verify the signature | |
echo "🔍 Verifying signature..." | |
codesign --verify --verbose "${{env.APP_NAME}}.app" | |
# Create the DMG from the signed app | |
echo "📦 Creating DMG from signed application..." | |
hdiutil create -volname "${{env.APP_NAME}}" -srcfolder "${{env.APP_NAME}}.app" -ov -format UDZO "${{env.APP_NAME}}.dmg" | |
# Sign the DMG | |
echo "🔏 Signing the DMG..." | |
codesign --force --sign "Developer ID Application: Dimitris Kalamaras (${{ secrets.AC_TEAM_ID }})" "${{env.APP_NAME}}.dmg" | |
# Before starting notarization, set keychain to not timeout | |
echo "🔐 Setting keychain to not timeout..." | |
security set-keychain-settings -t 72000 -l build.keychain | |
# Notarize the signed DMG | |
echo "📜 Notarize the DMG" | |
SUBMIT_OUTPUT=$(xcrun notarytool submit "${{env.APP_NAME}}.dmg" --keychain-profile "AC_PASSWORD") | |
NOTARY_SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep "id:" | head -1 | awk '{print $2}') | |
echo "Notarization submission ID: $NOTARY_SUBMISSION_ID" | |
if [[ -z "$NOTARY_SUBMISSION_ID" ]]; then | |
echo "❌ Error: Notarization submission ID is empty!" | |
exit 1 | |
fi | |
# Store the submission id | |
echo "NOTARY_SUBMISSION_ID=$NOTARY_SUBMISSION_ID" >> $GITHUB_ENV | |
echo "🕒 Waiting for notarization to complete (with timeout)..." | |
START_TIME=$(date +%s) | |
TIMEOUT_SECONDS=1800 # 30 minutes timeout | |
while true; do | |
# Check if we've exceeded the timeout | |
CURRENT_TIME=$(date +%s) | |
ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) | |
if [[ $ELAPSED_TIME -gt $TIMEOUT_SECONDS ]]; then | |
echo "⚠️ Notarization timeout after $(($TIMEOUT_SECONDS / 60)) minutes" | |
break | |
fi | |
# Explicitly unlock the keychain again before checking status | |
echo "🔓 Unlocking keychain before checking notarization status..." | |
security unlock-keychain -p "" build.keychain | |
# Check notarization status | |
echo "🔍 Checking notarization status..." | |
NOTARY_INFO=$(xcrun notarytool info --keychain-profile "AC_PASSWORD" "$NOTARY_SUBMISSION_ID" 2>&1) | |
echo "$NOTARY_INFO" | |
# Extract status | |
NOTARY_STATUS=$(echo "$NOTARY_INFO" | grep -i "status:" | awk '{print $2}' | tr -d '[:space:]') | |
if [[ "$NOTARY_STATUS" == "Accepted" ]]; then | |
echo "✅ Notarization successful!" | |
# Staple the notarization ticket to the DMG | |
echo "📌 Stapling notarization ticket to DMG..." | |
xcrun stapler staple "${{env.APP_NAME}}.dmg" | |
# Rename DMG file after successful notarization and stapling | |
DMG_NAME="${{env.APP_NAME}}-${{env.VERSION}}.dmg" | |
mv "${{env.APP_NAME}}.dmg" "${DMG_NAME}" | |
echo "🎉 Build, signing, notarization and stapling complete. Final DMG: ${DMG_NAME}" | |
ls -lh *.dmg | |
echo "MAC_ARTIFACT=${DMG_NAME}" >> $GITHUB_ENV | |
break | |
elif [[ "$NOTARY_STATUS" == "Invalid" || "$NOTARY_STATUS" == "Rejected" ]]; then | |
echo "❌ Notarization failed. Details:" | |
echo "$notarization_info" | |
# Get logs for failure details | |
xcrun notarytool log --keychain-profile "AC_PASSWORD" "$NOTARY_SUBMISSION_ID" | |
# Still create the artifact, but with a different name to indicate it's not notarized | |
DMG_NAME="${{env.APP_NAME}}-${{env.VERSION}}-unsigned.dmg" | |
mv "${{env.APP_NAME}}.dmg" "${DMG_NAME}" | |
echo "⚠️ Created unsigned DMG: ${DMG_NAME}" | |
echo "MAC_ARTIFACT=${DMG_NAME}" >> $GITHUB_ENV | |
break | |
elif [[ "$NOTARY_STATUS" == "In Progress" ]]; then | |
echo "⏳ Notarization still in progress, waiting..." | |
elif [[ "$NOTARY_STATUS" == "InProgress" ]]; then | |
echo "⏳ Notarization still in progress, waiting..." | |
else | |
echo "⚠️ Unexpected status: $NOTARY_STATUS" | |
echo "$NOTARY_INFO" | |
fi | |
echo "⏳ Still waiting for notarization... ($(($ELAPSED_TIME / 60)) minutes elapsed)" | |
sleep 60 # Check every minute | |
done | |
- if: contains( matrix.os, 'macos') && matrix.qt-version == '6.8.0' && env.MAC_ARTIFACT != '' | |
name: 📤 Upload ${{matrix.os}} build artifacts of ${{env.APP_NAME}} ${{ env.VERSION }} to GitHub ${{ env.UPLOAD_URL }} | |
run: | | |
echo "🔍 Verifying artifact: ${{ env.MAC_ARTIFACT }}" | |
pwd | |
ls build | |
if [ ! -f "./build/${{ env.MAC_ARTIFACT }}" ]; then | |
echo "❌ Error: Artifact not found!" | |
exit 1 | |
fi | |
echo "📤 Uploading artifact to GitHub release..." | |
gh release upload continuous "./build/${{ env.MAC_ARTIFACT }}" --repo "${{ github.repository }}" \ | |
--clobber | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
# Upload artifacts from macOS build to 'continuous' pre-release tag | |
# - if: contains( matrix.os, 'macos') && matrix.qt-version == '6.8.0' && env.MAC_ARTIFACT != '' | |
# name: Upload ${{matrix.os}} build artifacts of ${{env.APP_NAME}} ${{ env.VERSION }} to GitHub ${{ env.UPLOAD_URL }} | |
# uses: actions/upload-release-asset@v1 | |
# with: | |
# upload_url: ${{ env.UPLOAD_URL }} | |
# asset_path: ./${{ env.MAC_ARTIFACT }} | |
# asset_name: "${{ env.MAC_ARTIFACT }}" | |
# asset_content_type: "application/octet-stream" | |
# env: | |
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
# BUILD FOR WINDOWS | |
- if: contains( matrix.os, 'windows') && matrix.qt-version == '6.5.3' | |
name: Build ${{env.APP_NAME}} ${{ env.VERSION }} for ${{matrix.os}} with Qt ${{matrix.qt-version}} using qmake. | |
run: | | |
echo "🔎 Listing some directories" | |
dir D:\a\app\Qt\ | |
echo "🔧 Running 'qmake6 CONFIG+=${{env.QMAKE_CONFIG}} ${{env.QMAKE_PROJECT}} -r' to configure the project on Windows..." | |
qmake6 CONFIG+=${{env.QMAKE_CONFIG}} TARGET.path=${{env.QMAKE_CONFIG}} ${{env.QMAKE_PROJECT}} -r | |
echo "🚧 🛠️ Compiling with nmake. Please wait..." | |
nmake | |
echo "👉 Building finished. Listing directory ${{env.QMAKE_CONFIG}} for verification:" | |
dir ${{env.QMAKE_CONFIG}} | |
- if: contains( matrix.os, 'windows') && matrix.qt-version != '6.5.3' | |
name: Build ${{env.APP_NAME}} ${{ env.VERSION }} for ${{matrix.os}} with Qt ${{matrix.qt-version}} using cmake. | |
run: | | |
echo "🔎 Listing some directories" | |
dir D:\a\app\Qt\ | |
echo "🔎 Verifying Qt installation path..." | |
where qmake | |
where windeployqt | |
echo "💡 Creating build dir" | |
mkdir build | |
echo "🔧 Running 'cmake -S . -B build' to configure the project..." | |
cmake -S . -B build | |
echo "🚧 🛠️ Compiling into build/ with 'cmake --build build -j${{env.CORES}} --config ${{env.CMAKE_CONFIG}}'. Please wait..." | |
cmake --build build -j${{env.CORES}} --config ${{env.CMAKE_CONFIG}} -v | |
echo "👉 Building finished. Entering build/ and listing it for verification: " | |
cd build | |
dir | |
echo "🔧 Running windeployqt on built executable (and ensuring required .dlls are copied into the folder)..." | |
windeployqt ${{env.CMAKE_CONFIG}}\socnetv.exe --release --compiler-runtime | |
echo "🔧 Manually copying MSVC runtime DLLs..." | |
if (!(Test-Path "C:\Windows\System32\MSVCP140_1.dll")) { | |
echo "❌ MSVCP140_1.dll NOT FOUND in System32! This may cause runtime errors." | |
exit 1 # Fail the build when the file is missing | |
} | |
if (!(Test-Path "C:\Windows\System32\MSVCP140_2.dll")) { | |
echo "❌ MSVCP140_2.dll NOT FOUND in System32! This may cause runtime errors." | |
exit 1 # Fail the build when the file is missing | |
} | |
copy "C:\Windows\System32\MSVCP140.dll" ${{env.CMAKE_CONFIG}}\ | |
copy "C:\Windows\System32\MSVCP140_1.dll" ${{env.CMAKE_CONFIG}}\ | |
copy "C:\Windows\System32\MSVCP140_2.dll" ${{env.CMAKE_CONFIG}}\ | |
copy "C:\Windows\System32\VCRUNTIME140.dll" ${{env.CMAKE_CONFIG}}\ | |
copy "C:\Windows\System32\VCRUNTIME140_1.dll" ${{env.CMAKE_CONFIG}}\ | |
copy "C:\Windows\System32\CONCRT140.dll" ${{env.CMAKE_CONFIG}}\ | |
echo "🔧 Copying license file to build directory..." | |
copy ..\COPYING ${{env.CMAKE_CONFIG}}\LICENSE.txt | |
echo "👉 Checking deployed DLLs..." | |
dir ${{env.CMAKE_CONFIG}} | |
if (!(Get-Command "iscc.exe" -ErrorAction SilentlyContinue)) { | |
echo "🔧 Installing Inno Setup..." | |
choco install -y InnoSetup | |
} else { | |
echo "Inno Setup is already installed. Skipping installation." | |
} | |
echo "🔧 Adding Inno Setup to PATH..." | |
$env:PATH += ";C:\Program Files (x86)\Inno Setup 6\" | |
echo "🔧 Verifying Inno Setup Installation..." | |
iscc.exe /? | |
echo "🔧 Copying InnoSetup script..." | |
copy ..\scripts\innosetup.iss innosetup.iss | |
echo "Updating RELEASEFOLDER in innosetup.iss with ${{env.CMAKE_CONFIG}}..." | |
$config = "${{env.CMAKE_CONFIG}}" | |
$replacement = "#define RELEASEFOLDER `"$config\\`"" | |
(Get-Content innosetup.iss) -replace '#define RELEASEFOLDER "release\\"', $replacement | Set-Content innosetup.iss | |
echo "Updated innosetup.iss:" | |
type innosetup.iss | |
echo "🔧 Running Inno Setup to create installer..." | |
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "innosetup.iss" | |
echo "👉 Checking if installer exists in current directory ..." | |
dir | |
$originalInstaller = Get-ChildItem -Path "SocNetV-*installer.exe" -ErrorAction SilentlyContinue | |
if (-not $originalInstaller) { | |
echo "❌ Error: Installer file not found!" | |
exit 1 | |
} | |
echo "🔧 Renaming installer..." | |
$installerName = "SocNetV-${{env.VERSION}}-windows-installer.exe" | |
Get-ChildItem -Path "SocNetV-*installer.exe" | Move-Item -Destination $installerName | |
dir | |
echo "🎉 Exporting installer name to environment variable..." | |
echo "WINDOWS_ARTIFACT=$installerName" >> $env:GITHUB_ENV | |
echo "🎉 Windows build complete. Artifacts are ready!" | |
- if: contains( matrix.os, 'windows') && matrix.qt-version == '6.8.0' && env.WINDOWS_ARTIFACT != '' | |
name: 📤 Upload ${{matrix.os}} build artifacts of ${{env.APP_NAME}} ${{ env.VERSION }} to GitHub ${{ env.UPLOAD_URL }} | |
run: | | |
echo "🔍 Verifying artifact: ${{ env.WINDOWS_ARTIFACT }}" | |
echo "Current working directory:" | |
pwd | |
echo "Contents of build directory:" | |
Get-ChildItem -Path build | |
if (!(Test-Path -Path "./build/${{ env.WINDOWS_ARTIFACT }}")) { | |
echo "❌ Error: Artifact not found!" | |
exit 1 | |
} | |
echo "📤 Uploading artifact to GitHub release..." | |
gh release upload continuous "./build/${{ env.WINDOWS_ARTIFACT }}" ` | |
--repo "${{ github.repository }}" ` | |
--clobber | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- run: echo "🍏 This job's status is ${{ job.status }}." | |
# Update the continuous release description (only once, from ubuntu) | |
- if: matrix.os == 'ubuntu-latest' && matrix.qt-version == '6.8.0' | |
name: 🔄 Update continuous release description | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
const commitSha = context.sha; | |
const shortSha = commitSha.slice(0, 7); | |
const commitDate = new Date().toISOString().split('T')[0]; | |
const { data: commit } = await github.rest.git.getCommit({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
commit_sha: commitSha | |
}); | |
const commitMessage = commit.message.split('\n')[0]; | |
const newDescription = `Latest Continuous Build. Built from commit \`${shortSha}\` on ${commitDate}. This is an automated continuous build. These builds are generated automatically from the latest \`develop\` code and are intended for testing purposes.`; | |
try { | |
// Find the continuous release | |
const { data: releases } = await github.rest.repos.listReleases({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
}); | |
const release = releases.find(r => r.tag_name === "continuous"); | |
if (release) { | |
// Update the release description | |
await github.rest.repos.updateRelease({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
release_id: release.id, | |
body: newDescription | |
}); | |
console.log("Release description updated successfully"); | |
} else { | |
console.log("Continuous release not found"); | |
} | |
} catch (error) { | |
console.error("Error updating release description:", error); | |
} | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |