Skip to content

Instantly share code, notes, and snippets.

@vasmarfas
Created May 26, 2025 15:50
Show Gist options
  • Save vasmarfas/8fa0db21027cccb5396bee9a8424c8b6 to your computer and use it in GitHub Desktop.
Save vasmarfas/8fa0db21027cccb5396bee9a8424c8b6 to your computer and use it in GitHub Desktop.
Gitlab CI for selfhosted Gitlab instance and workers (macOS + Windows) on example DotaDiviner app
stages:
- build
- upload
- create_release
- update_files
variables:
ANDROID_HOME: "C:/Users/*user*/AppData/Local/Android/Sdk"
JAVA_HOME: "C:/Program Files/Java/jdk-21"
before_script:
- echo "Setting up environment variables"
# - export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH
# - export PATH=$JAVA_HOME/bin:$PATH
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
#- echo "Cleaning up old build files"
#- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
- echo "Reading version from file"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- echo "Version $VERSION"
build_apk:
stage: build
tags:
- winserver
before_script:
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
- echo "Reading version from file"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- echo "Version $VERSION"
#- echo "Cleaning up old build files"
#- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
script:
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
#- echo "Cleaning up old build files"
#- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
- echo "Building APK"
- ./gradlew assembleRelease
# - $VERSION = Get-Content -Path "mainProjectVersion.txt"
- echo "Version $VERSION"
- cp -Force ./composeApp/build/outputs/apk/release/composeApp-release.apk ../outFile/DotaDiviner-$VERSION.apk # Переименование APK
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
artifacts:
paths:
- "outFiles/DotaDiviner-$VERSION.apk" # Указываем новое имя, и оно будет корректно подставлено
- outFiles/DotaDiviner-$VERSION.apk # Указываем новое имя, и оно будет корректно подставлено
only:
- master
build_aab:
stage: build
tags:
- winserver
before_script:
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
#- echo "Cleaning up old build files"
#- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
script:
- echo "Building AAB"
- ./gradlew bundleRelease
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- echo "Version $VERSION"
- cp -Force ./composeApp/build/outputs/bundle/release/composeApp-release.aab ../outFile/DotaDiviner-$VERSION.aab # Переименование AAB
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
artifacts:
paths:
- outFiles/DotaDiviner-$VERSION.aab # Указываем новое имя
only:
- master
build_msi:
stage: build
tags:
- winserver
variables:
GRADLE_USER_HOME: "C:/Users/*user*/.gradle"
before_script:
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
#- echo "Cleaning up old build files"
#- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
script:
- echo "Building MSI using batch file"
- ./gradlew clean
- echo "Forcing Wix download"
- ./gradlew downloadWix --rerun-tasks
- echo "Checking if Wix is properly downloaded"
- if (Test-Path "C:\Users\*user*\.gradle\compose-jb\wix311.zip") { echo "Wix ZIP exists" } else { echo "Wix ZIP missing"; exit 1 }
- ./gradlew packageMsi
- echo "Searching for MSI file"
- $MSI_FILE = Get-ChildItem -Path "composeApp/build/compose/binaries/main/msi" -Filter "DotaDiviner*.msi" | Select-Object -First 1
- echo "Found MSI file $MSI_FILE"
- msiSigning/signtool.exe sign /fd SHA256 /f msiSigning/cert.pfx /p "password" /t http://timestamp.digicert.com "$MSI_FILE"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- echo "Signing completed for $MSI_FILE"
# Перемещаем подписанный файл в нужную директорию для артефактов
- cp -Force $MSI_FILE ../outFile/DotaDiviner-$VERSION.msi
- echo "Terminating Java processes"
- taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
artifacts:
paths:
- outFiles/DotaDiviner-$VERSION.msi
only:
- master
# iOS и macOS задачи
build_ios:
stage: build
tags:
- macos-mini
variables:
JAVA_HOME: "$HOME/jdk/Home"
before_script:
- echo "Настройка CI окружения для iOS сборки"
# Разблокировка основной связки DotaDivinerCI.keychain
- security unlock-keychain -p "keychain-password" DotaDivinerCI.keychain
- security set-keychain-settings -t 7200 -l DotaDivinerCI.keychain
# Разблокировка всех системных связок ключей
- security unlock-keychain -p "keychain-password" "$HOME/Library/Keychains/login.keychain-db"
- security unlock-keychain -p "keychain-password" "$HOME/Library/Keychains/login.keychain-db"
- security set-keychain-settings -t 7200 -l "$HOME/Library/Keychains/login.keychain-db"
# Если у вас есть TemporDotaDivinerKeychain, разблокируем её тоже
- |
if [ -f "$HOME/Library/Keychains/TemporDotaDivinerKeychain.keychain-db" ]; then
security unlock-keychain -p "keychain-password" "$HOME/Library/Keychains/TemporDotaDivinerKeychain.keychain-db"
security set-keychain-settings -t 7200 -l "$HOME/Library/Keychains/TemporDotaDivinerKeychain.keychain-db"
fi
# Устанавливаем порядок поиска в связках ключей (DotaDivinerCI первым)
- security list-keychains -d user -s DotaDivinerCI.keychain "$HOME/Library/Keychains/login.keychain-db" "/Library/Keychains/System.keychain"
# Настройка разделов для всех связок
- 'security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "keychain-password" DotaDivinerCI.keychain'
- 'security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "keychain-password" "$HOME/Library/Keychains/TemporDotaDivinerKeychain.keychain-db"'
# Отображение доступных сертификатов
- security find-identity -v -p codesigning
# Проверяем доступность xcodebuild
- xcrun xcodebuild -version
script: |
cd iosApp
xcodebuild -project iosApp.xcodeproj \
-scheme iosApp \
-sdk iphoneos \
-configuration Release \
-archivePath ../outIos/iosApp.xcarchive \
archive \
CODE_SIGNING_REQUIRED=YES \
CODE_SIGNING_ALLOWED=YES
cd ..
xcodebuild -exportArchive \
-archivePath outIos/iosApp.xcarchive \
-exportPath outIos/ipa \
-exportOptionsPlist ExportOptions.plist
artifacts:
paths:
- "outIos/ipa/Dota Diviner.ipa"
only:
- master
build_macos:
stage: build
tags:
- macos-mini
variables:
JAVA_HOME: "$HOME/jdk/Home"
before_script:
- echo "Настройка CI окружения для macOS сборки"
- security unlock-keychain -p "keychain-password" DotaDivinerCI.keychain
- security set-keychain-settings -t 7200 -l DotaDivinerCI.keychain
- security list-keychains -d user -s DotaDivinerCI.keychain "$HOME/Library/Keychains/login.keychain-db" "/Library/Keychains/System.keychain"
- 'security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "keychain-password" DotaDivinerCI.keychain'
# Отображение доступных сертификатов
- security find-identity -v -p codesigning
# Проверяем JAVA_HOME
- export JAVA_HOME="$HOME/jdk/Home"
- echo "JAVA_HOME=$JAVA_HOME"
# Проверяем доступность xcodebuild
- xcrun xcodebuild -version
script: |
echo "Building macOS app"
cd $CI_PROJECT_DIR
export VERSION=$(cat mainProjectVersion.txt)
echo "Building macOS app version $VERSION"
# Для решения проблемы с версией (3.02.23 vs 3.2.23)
# Выводим информацию о текущей версии
echo "Текущий формат версии: $VERSION"
# Аналогично ci_pre_xcodebuild.sh в Xcode Cloud
./gradlew commonizeNativeDistribution
./gradlew :composeApp:packageReleasePkg -PmacOsAppStoreRelease=true
echo "macOS app build completed"
# Проверяем создались ли файлы
echo "Checking for created .pkg files:"
find composeApp/build -name "*.pkg" -type f || echo "No .pkg files found"
# Проверяем конкретную директорию
if [ -d "composeApp/build/compose/binaries/main/pkg" ]; then
echo "Directory composeApp/build/compose/binaries/main/pkg exists:"
ls -la composeApp/build/compose/binaries/main/pkg/
else
echo "Directory composeApp/build/compose/binaries/main/pkg does not exist"
echo "Available build directories:"
find composeApp/build -type d -name "*pkg*" || echo "No pkg directories found"
fi
artifacts:
paths:
- composeApp/build/compose/binaries/main-release/pkg/DotaDiviner-*.pkg
only:
- master
# build_wasmjs:
# stage: build
# tags:
# - winserver
# before_script:
# - echo "Terminating Java processes"
# - taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
# #- echo "Cleaning up old build files"
# #- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
# script:
# - echo "Building WASM"
# - ./gradlew kotlinUpgradeYarnLock
# - ./gradlew wasmJsBrowserDistribution
# - $VERSION = Get-Content -Path "mainProjectVersion.txt"
# - echo "Version $VERSION"
# - echo "Zipping productionExecutable"
# - powershell -Command "Compress-Archive -Path './composeApp/build/dist/wasmJs/productionExecutable/' -DestinationPath './outFiles/productionExecutable-$VERSION.zip'"
# - cp -Force ./outFiles/productionExecutable-$VERSION.zip ../outFile/DotaDiviner-$VERSION.zip
# - echo "Terminating Java processes"
# - taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
# artifacts:
# paths:
# - outFiles/productionExecutable-$VERSION.zip
# only:
# - master
build_wasmjs_on_mac:
stage: build
tags:
- macos-mini
before_script:
- echo "Setting correct JAVA_HOME for macOS"
- export JAVA_HOME=$(/usr/libexec/java_home)
- java -version
script:
- echo "Building WASM"
- ./gradlew kotlinUpgradeYarnLock
- ./gradlew wasmJsBrowserDistribution
- VERSION=$(cat mainProjectVersion.txt)
- echo "Version $VERSION"
- echo "Zipping productionExecutable"
- mkdir -p outFiles
- mkdir -p ../outFile
- zip -r "./outFiles/productionExecutable-$VERSION.zip" ./composeApp/build/dist/wasmJs/productionExecutable/
- cp -f "./outFiles/productionExecutable-$VERSION.zip" "../outFile/DotaDiviner-$VERSION.zip"
artifacts:
paths:
- outFiles/productionExecutable-$VERSION.zip
only:
- master
#build_js:
# stage: build
# tags:
# - winserver
# before_script:
# - echo "Terminating Java processes"
# - taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
# #- echo "Cleaning up old build files"
# #- Remove-Item -Path "composeApp/build" -Recurse -Force -ErrorAction SilentlyContinue
# script:
# - echo "Building JS"
# - ./gradlew kotlinUpgradeYarnLock
# - ./gradlew jsBrowserDistribution
# - $VERSION = Get-Content -Path "mainProjectVersion.txt"
# - echo "Version $VERSION"
# - echo "Zipping productionExecutable"
# - powershell -Command "Compress-Archive -Path './composeApp/build/dist/js/productionExecutable/' -DestinationPath './outFiles/productionExecutableJs-$VERSION.zip'"
# - cp -Force ./outFiles/productionExecutableJs-$VERSION.zip ../outFile/DotaDivinerJs-$VERSION.zip
# - echo "Terminating Java processes"
# - taskkill /F /IM java.exe /T 2>$null; if ($LASTEXITCODE -eq 0) { echo 'Java.exe terminated' } else { echo 'No Java.exe processes found' }
#
# artifacts:
# paths:
# - outFiles/productionExecutable-$VERSION.zip
# only:
# - master
build_js_on_mac:
stage: build
tags:
- macos-mini
before_script:
- echo "Setting correct JAVA_HOME for macOS"
- export JAVA_HOME=$(/usr/libexec/java_home)
- java -version
script:
- echo "Building JS"
- ./gradlew kotlinUpgradeYarnLock
- ./gradlew jsBrowserDistribution
- VERSION=$(cat mainProjectVersion.txt)
- echo "Version $VERSION"
- echo "Zipping productionExecutable"
- mkdir -p outFiles
- mkdir -p ../outFile
- zip -r "./outFiles/productionExecutableJs-$VERSION.zip" ./composeApp/build/dist/js/productionExecutable/
- cp -f "./outFiles/productionExecutableJs-$VERSION.zip" "../outFile/DotaDivinerJs-$VERSION.zip"
artifacts:
paths:
- outFiles/productionExecutableJs-$VERSION.zip
only:
- master
upload_apk:
stage: upload
tags:
- winserver
script:
- echo "Uploading APK file..."
- echo "Current Directory $(Get-Location)"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- if (-not $VERSION) {
Write-Error "Version not found in mainProjectVersion.txt"
exit 1
}
- $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
- $headers.Add("x-api-key", "apikey")
- $headers.Add("Albumuuid", "uuid")
- $APK_FILE = "../outFile/DotaDiviner-$VERSION.apk"
- echo "APK_FILE is $APK_FILE"
- if (!(Test-Path $APK_FILE)) { Write-Error "APK file not found $APK_FILE"; exit 1 }
- $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
- echo "Current Directory $(Get-Location)"
- $fullPathApk = (Get-Item "../outFile/DotaDiviner-$VERSION.apk").FullName
- echo "Full path $fullPathApk"
- |
if (!(Test-Path $fullPathApk)) {
Write-Error "File not found: $fullPathApk"
exit 1
}
- $FileStream = [System.IO.FileStream]::new($fullPathApk, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
- $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
- $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
- $fileHeader.Name = "file"
- $fileHeader.FileName = (Split-Path $fullPathApk -Leaf)
- $fileContent.Headers.ContentDisposition = $fileHeader
- $multipartContent.Add($fileContent)
- |
try {
$response = Invoke-RestMethod 'https://chibisafe' -Method 'POST' -Headers $headers -Body $multipartContent
echo "Response from API: $($response | ConvertTo-Json -Depth 10)"
if ($response -and $response.url) {
$UPLOAD_URL_APK = $response.url
echo "UPLOAD_URL_APK=$UPLOAD_URL_APK"
# Записываем в переменную окружения GitLab
echo "UPLOAD_URL_APK=$UPLOAD_URL_APK" | Out-File -FilePath "$CI_PIPELINE_ID.env" -Append
Write-Output "Upload successful: $UPLOAD_URL_APK"
echo "UPLOAD_URL_APK=$UPLOAD_URL_APK" | Out-File -FilePath "upload_apk.env"
} else {
Write-Error "Upload failed: No URL returned"
exit 1
}
} catch {
Write-Error "Upload failed: $_"
exit 1
}
artifacts:
reports:
dotenv: upload_apk.env
upload_aab:
stage: upload
tags:
- winserver
script:
- echo "Uploading AAB file..."
- echo "Current Directory $(Get-Location)"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- if (-not $VERSION) {
Write-Error "Version not found in mainProjectVersion.txt"
exit 1
}
- $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
- $headers.Add("x-api-key", "apikey")
- $headers.Add("Albumuuid", "uuid")
- $AAB_FILE = "../outFile/DotaDiviner-$VERSION.aab"
- echo "AAB_FILE is $AAB_FILE"
- if (!(Test-Path $AAB_FILE)) { Write-Error "AAB file not found $AAB_FILE"; exit 1 }
- $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
- echo "Current Directory $(Get-Location)"
- $fullPathAab = (Get-Item "../outFile/DotaDiviner-$VERSION.aab").FullName
- echo "Full path $fullPathAab"
- |
if (!(Test-Path $fullPathAab)) {
Write-Error "File not found: $fullPathAab"
exit 1
}
- $FileStream = [System.IO.FileStream]::new($fullPathAab, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
- $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
- $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
- $fileHeader.Name = "file"
- $fileHeader.FileName = (Split-Path $fullPathAab -Leaf)
- $fileContent.Headers.ContentDisposition = $fileHeader
- $multipartContent.Add($fileContent)
- |
try {
$response = Invoke-RestMethod 'https://chibisafe' -Method 'POST' -Headers $headers -Body $multipartContent
echo "Response from API: $($response | ConvertTo-Json -Depth 10)"
if ($response -and $response.url) {
$UPLOAD_URL_AAB = $response.url
echo "UPLOAD_URL_AAB=$UPLOAD_URL_AAB"
# Записываем в переменную окружения GitLab
echo "UPLOAD_URL_AAB=$UPLOAD_URL_AAB" | Out-File -FilePath "$CI_PIPELINE_ID.env" -Append
Write-Output "Upload successful: $UPLOAD_URL_AAB"
echo "UPLOAD_URL_AAB=$UPLOAD_URL_AAB" | Out-File -FilePath "upload_aab.env"
} else {
Write-Error "Upload failed: No URL returned"
exit 1
}
} catch {
Write-Error "Upload failed: $_"
exit 1
}
artifacts:
reports:
dotenv: upload_aab.env
upload_msi:
stage: upload
tags:
- winserver
script:
- echo "Uploading MSI file..."
- echo "Current Directory $(Get-Location)"
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- if (-not $VERSION) {
Write-Error "Version not found in mainProjectVersion.txt"
exit 1
}
- $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
- $headers.Add("x-api-key", "apikey")
- $headers.Add("Albumuuid", "uuid")
- $MSI_FILE = "../outFile/DotaDiviner-$VERSION.msi"
- echo "MSI_FILE is $MSI_FILE"
- if (!(Test-Path $MSI_FILE)) { Write-Error "MSI file not found $MSI_FILE"; exit 1 }
- $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
- echo "Current Directory $(Get-Location)"
- $fullPathMsi = (Get-Item "../outFile/DotaDiviner-$VERSION.msi").FullName
- echo "Full path $fullPathMsi"
- |
if (!(Test-Path $fullPathMsi)) {
Write-Error "File not found: $fullPathMsi"
exit 1
}
- $FileStream = [System.IO.FileStream]::new($fullPathMsi, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
- $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
- $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
- $fileHeader.Name = "file"
- $fileHeader.FileName = (Split-Path $fullPathMsi -Leaf)
- $fileContent.Headers.ContentDisposition = $fileHeader
- $multipartContent.Add($fileContent)
- |
try {
$response = Invoke-RestMethod 'https://chibisafe' -Method 'POST' -Headers $headers -Body $multipartContent
echo "Response from API: $($response | ConvertTo-Json -Depth 10)"
if ($response -and $response.url) {
$UPLOAD_URL_MSI = $response.url
echo "UPLOAD_URL_MSI=$UPLOAD_URL_MSI"
# Записываем в переменную окружения GitLab
echo "UPLOAD_URL_MSI=$UPLOAD_URL_MSI" | Out-File -FilePath "$CI_PIPELINE_ID.env" -Append
Write-Output "Upload successful: $UPLOAD_URL_MSI"
echo "UPLOAD_URL_MSI=$UPLOAD_URL_MSI" | Out-File -FilePath "upload_msi.env"
} else {
Write-Error "Upload failed: No URL returned"
exit 1
}
} catch {
Write-Error "Upload failed: $_"
exit 1
}
- echo "Uploading MSI file to remote server..."
- where ssh
- $KEY_FILE = New-TemporaryFile
- $KEY_FILE_PATH = $KEY_FILE.FullName
- $SSH_PRIVATE_KEY_ORACLE_MICRO_FIRST | Out-File -Encoding ascii -FilePath $KEY_FILE_PATH
- icacls $KEY_FILE_PATH /inheritance:r /grant *S-1-5-32-544:F
- scp -o StrictHostKeyChecking=no -i "$KEY_FILE_PATH" "$fullPathMsi" "ubuntu@ipaddr:/var/www/appdownloads/DotaDiviner.msi"
- Remove-Item -Force $KEY_FILE_PATH
artifacts:
reports:
dotenv: upload_msi.env
upload_ios:
stage: upload
tags:
- macos-mini
before_script: []
script: |
xcrun altool --upload-app \
--type ios \
--file "outIos/ipa/Dota Diviner.ipa" \
--username "[email protected]" \
--password "xxxx-xxxx-xxxx-xxxx"
echo "iOS app uploaded to App Store Connect successfully"
dependencies:
- build_ios
only:
- master
upload_macos:
stage: upload
tags:
- macos-mini
before_script: []
script: |
echo "Uploading macOS app to App Store Connect"
export VERSION=$(cat mainProjectVersion.txt)
# Проверяем существование директории (сначала пробуем main-release, потом main)
PKG_DIR=""
if [ -d "composeApp/build/compose/binaries/main-release/pkg" ]; then
PKG_DIR="composeApp/build/compose/binaries/main-release/pkg"
echo "Found pkg directory: $PKG_DIR"
elif [ -d "composeApp/build/compose/binaries/main/pkg" ]; then
PKG_DIR="composeApp/build/compose/binaries/main/pkg"
echo "Found pkg directory: $PKG_DIR"
else
echo "ERROR: Neither main-release nor main pkg directory exists"
echo "Available directories:"
find composeApp/build -name "*.pkg" -type f 2>/dev/null || echo "No .pkg files found"
find composeApp/build -type d -name "*pkg*" 2>/dev/null || echo "No pkg directories found"
exit 1
fi
PKG_FILE=$(find "$PKG_DIR" -name "DotaDiviner-*.pkg" | head -n 1)
if [ -z "$PKG_FILE" ]; then
echo "ERROR: No .pkg file found in $PKG_DIR"
echo "Directory contents:"
ls -la "$PKG_DIR/" || echo "Directory does not exist"
exit 1
fi
echo "Found PKG file: $PKG_FILE"
/usr/bin/xcrun altool --upload-app -f "$PKG_FILE" -t macos -u "[email protected]" -p "xxxx-xxxx-xxxx-xxxx" --show-progress --verbose
echo "Релиз успешно завершен!"
dependencies:
- build_macos
only:
- master
# upload_wasm:
# stage: upload
# tags:
# - winserver
# script:
# - echo "Uploading WASM file..."
# - echo "Current Directory $(Get-Location)"
# - $VERSION = Get-Content -Path "mainProjectVersion.txt"
# - if (-not $VERSION) {
# Write-Error "Version not found in mainProjectVersion.txt"
# exit 1
# }
# - $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
# - $headers.Add("x-api-key", "apikey")
# - $headers.Add("Albumuuid", "uuid")
# - $WASM_FILE = "../outFile/DotaDiviner-$VERSION.zip"
# - echo "WASM_FILE is $WASM_FILE"
# - if (!(Test-Path $WASM_FILE)) { Write-Error "WASM file not found $WASM_FILE"; exit 1 }
# - $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
# - echo "Current Directory $(Get-Location)"
# - $fullPathWasm = (Get-Item "../outFile/DotaDiviner-$VERSION.zip").FullName
# - echo "Full path $fullPathWasm"
# - |
# if (!(Test-Path $fullPathWasm)) {
# Write-Error "File not found: $fullPathWasm"
# exit 1
# }
# - $FileStream = [System.IO.FileStream]::new($fullPathWasm, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
# - $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
# - $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
# - $fileHeader.Name = "file"
# - $fileHeader.FileName = (Split-Path $fullPathWasm -Leaf)
# - $fileContent.Headers.ContentDisposition = $fileHeader
# - $multipartContent.Add($fileContent)
# - |
# try {
# $response = Invoke-RestMethod 'https://chibisafe' -Method 'POST' -Headers $headers -Body $multipartContent
# echo "Response from API: $($response | ConvertTo-Json -Depth 10)"
# if ($response -and $response.url) {
# $UPLOAD_URL_WASM = $response.url
# echo "UPLOAD_URL_WASM=$UPLOAD_URL_WASM"
# # Записываем в переменную окружения GitLab
# echo "UPLOAD_URL_WASM=$UPLOAD_URL_WASM" | Out-File -FilePath "$CI_PIPELINE_ID.env" -Append
# Write-Output "Upload successful: $UPLOAD_URL_WASM"
# echo "UPLOAD_URL_WASM=$UPLOAD_URL_WASM" | Out-File -FilePath "upload_wasm.env"
# } else {
# Write-Error "Upload failed: No URL returned"
# exit 1
# }
# } catch {
# Write-Error "Upload failed: $_"
# exit 1
# }
# artifacts:
# reports:
# dotenv: upload_wasm.env
upload_wasm_on_macos:
stage: upload
tags:
- macos-mini
before_script: [ ]
script:
- echo "Uploading WASM file..."
- echo "Current Directory $(pwd)"
- VERSION=$(cat mainProjectVersion.txt)
- if [ -z "$VERSION" ]; then
echo "Version not found in mainProjectVersion.txt" >&2;
exit 1;
fi
- WASM_FILE="../outFile/DotaDiviner-$VERSION.zip"
- echo "WASM_FILE is $WASM_FILE"
- |
if [ ! -f "$WASM_FILE" ]; then
echo "WASM file not found: $WASM_FILE" >&2;
exit 1;
fi
- echo "Current Directory $(pwd)"
- FULL_PATH_WASM=$(realpath "$WASM_FILE")
- echo "Full path $FULL_PATH_WASM"
# Выполняем multipart-загрузку через curl
- |
RESPONSE=$(curl -s -w "%{http_code}" -o response.json -X POST "https://chibisafe" \
-H "x-api-key: apikey" \
-H "Albumuuid: uuid" \
-F "file=@$FULL_PATH_WASM")
- 'echo "HTTP status: $RESPONSE"'
- echo "API response:"
- cat response.json
- if [ "$RESPONSE" -ne 200 ]; then
echo "Upload failed with HTTP status $RESPONSE" >&2;
exit 1;
fi
- UPLOAD_URL_WASM=$(jq -r '.url' response.json)
- |
if [ "$UPLOAD_URL_WASM" == "null" ] || [ -z "$UPLOAD_URL_WASM" ]; then
echo "Upload failed: No URL returned" >&2;
exit 1;
fi
- echo "UPLOAD_URL_WASM=$UPLOAD_URL_WASM"
- echo "UPLOAD_URL_WASM=$UPLOAD_URL_WASM" >> upload_wasm.env
artifacts:
reports:
dotenv: upload_wasm.env
#upload_js:
# stage: upload
# tags:
# - winserver
# script:
# - echo "Uploading JS file..."
# - echo "Current Directory $(Get-Location)"
# - $VERSION = Get-Content -Path "mainProjectVersion.txt"
# - if (-not $VERSION) {
# Write-Error "Version not found in mainProjectVersion.txt"
# exit 1
# }
# - $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
# - $headers.Add("x-api-key", "apikey")
# - $headers.Add("Albumuuid", "uuid")
# - $JS_FILE = "../outFile/DotaDivinerJs-$VERSION.zip"
# - echo "JS_FILE is $JS_FILE"
# - if (!(Test-Path $JS_FILE)) { Write-Error "JS file not found $JS_FILE"; exit 1 }
# - $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
# - echo "Current Directory $(Get-Location)"
# - $fullPathJS = (Get-Item "../outFile/DotaDivinerJs-$VERSION.zip").FullName
# - echo "Full path $fullPathJS"
# - |
# if (!(Test-Path $fullPathJS)) {
# Write-Error "File not found: $fullPathJS"
# exit 1
# }
#
# - $FileStream = [System.IO.FileStream]::new($fullPathJS, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
# - $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
# - $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
# - $fileHeader.Name = "file"
# - $fileHeader.FileName = (Split-Path $fullPathJS -Leaf)
# - $fileContent.Headers.ContentDisposition = $fileHeader
# - $multipartContent.Add($fileContent)
# - |
# try {
# $response = Invoke-RestMethod 'https://chibisafe' -Method 'POST' -Headers $headers -Body $multipartContent
#
# echo "Response from API: $($response | ConvertTo-Json -Depth 10)"
#
# if ($response -and $response.url) {
# $UPLOAD_URL_JS = $response.url
# echo "UPLOAD_URL_JS=$UPLOAD_URL_JS"
#
# # Записываем в переменную окружения GitLab
# echo "UPLOAD_URL_JS=$UPLOAD_URL_JS" | Out-File -FilePath "$CI_PIPELINE_ID.env" -Append
# Write-Output "Upload successful: $UPLOAD_URL_JS"
# echo "UPLOAD_URL_JS=$UPLOAD_URL_JS" | Out-File -FilePath "upload_js.env"
# } else {
# Write-Error "Upload failed: No URL returned"
# exit 1
# }
# } catch {
# Write-Error "Upload failed: $_"
# exit 1
# }
# artifacts:
# reports:
# dotenv: upload_js.env
upload_js_on_macos:
stage: upload
tags:
- macos-mini
before_script: [ ]
script:
- echo "Uploading JS file..."
- echo "Current Directory $(pwd)"
- VERSION=$(cat mainProjectVersion.txt)
- if [ -z "$VERSION" ]; then
echo "Version not found in mainProjectVersion.txt" >&2;
exit 1;
fi
- $JS_FILE="../outFile/DotaDivinerJs-$VERSION.zip"
- echo "JS_FILE is $JS_FILE"
- |
if [ ! -f "$JS_FILE" ]; then
echo "JS file not found: $JS_FILE" >&2;
exit 1;
fi
- echo "Current Directory $(pwd)"
- FULL_PATH_JS=$(realpath "$JS_FILE")
- echo "Full path $FULL_PATH_JS"
# Выполняем multipart-загрузку через curl
- |
RESPONSE=$(curl -s -w "%{http_code}" -o response.json -X POST "https://chibisafe" \
-H "x-api-key: apikey" \
-H "Albumuuid: uuid" \
-F "file=@$FULL_PATH_JS")
- 'echo "HTTP status: $RESPONSE"'
- echo "API response:"
- cat response.json
- if [ "$RESPONSE" -ne 200 ]; then
echo "Upload failed with HTTP status $RESPONSE" >&2;
exit 1;
fi
- UPLOAD_URL_JS=$(jq -r '.url' response.json)
- |
if [ "$UPLOAD_URL_JS" == "null" ] || [ -z "$UPLOAD_URL_JS" ]; then
echo "Upload failed: No URL returned" >&2;
exit 1;
fi
- echo "UPLOAD_URL_JS=$UPLOAD_URL_JS"
- echo "UPLOAD_URL_JS=$UPLOAD_URL_JS" >> upload_js.env
artifacts:
reports:
dotenv: upload_js.env
create_release:
stage: create_release
tags:
- winserver
script:
- echo "Creating or updating GitLab Release..."
- $VERSION = Get-Content -Path "mainProjectVersion.txt"
- $VERSION_COMMITHASH = $(git rev-parse --short HEAD)
- $VERSION_TAG = "$VERSION" + "_" + "$VERSION_COMMITHASH"
- echo "VERSION_TAG=$VERSION_TAG" >> build.env
- $PIPELINE_ID = $env:CI_PIPELINE_ID
- $DATE = Get-Date -Format "dd-MM-yyyy HH:mm:ss"
- $DESCRIPTION = "Version $VERSION`nCommit $VERSION_COMMITHASH`nPipeline ID $PIPELINE_ID`nDate $DATE"
- $RELEASE_TAG = "$VERSION_TAG"
- echo "RELEASE_TAG=$RELEASE_TAG" | Out-File -FilePath "create_release.env"
- Write-Host "Ищем релиз с тегом $VERSION_TAG"
- |
try {
$response = Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$VERSION_TAG" `
-Method GET `
-Headers @{"PRIVATE-TOKEN" = "glpat-token"}
} catch {
if ($_.Exception.Response.StatusCode -eq 404) {
Write-Host "Релиз не найден (404). Создадим новый."
$response = $null
} else {
throw $_ # Прочие ошибки пробрасываем дальше
}
}
- Write-Host "GitLab API response $($response | ConvertTo-Json -Depth 10)"
# Если релиз существует, добавляем файл, иначе создаем новый релиз
- |
if ($response) {
Write-Host "Релиз с версией $VERSION_TAG уже существует. "
$RELEASE_ID = $response[0].id
} else {
Write-Host "Релиз с версией $VERSION_TAG не существует. Создаем новый релиз..."
$CREATE_RELEASE_DATA = @{
"tag_name" = "$VERSION_TAG";
"name" = "Release $VERSION ($VERSION_COMMITHASH)";
"description" = "$DESCRIPTION";
"ref" = "master"
}
$CREATE_RELEASE_RESPONSE = Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases" `
-Method POST `
-Headers @{"PRIVATE-TOKEN" = "glpat-token"; "Content-Type" = "application/json"} `
-Body ($CREATE_RELEASE_DATA | ConvertTo-Json -Depth 10)
Write-Host "Релиз $VERSION_TAG успешно создан."
}
artifacts:
reports:
dotenv: create_release.env
update_apk:
stage: update_files
tags:
- winserver
needs:
- job: upload_apk
artifacts: true
- create_release
script:
- Write-Output "$UPLOAD_URL_APK"
- Write-Output "$VERSION_TAG"
- echo "$VERSION_TAG"
- echo "Adding APK to GitLab Release..."
- echo "Release tag $RELEASE_TAG"
- if (!$RELEASE_TAG) { Write-Error "RELEASE_TAG is missing"; exit 1 }
- $UPLOAD_URL_APK = $env:UPLOAD_URL_APK
- if (!$UPLOAD_URL_APK) { Write-Error "UPLOAD_URL_APK is missing"; exit 1 }
- |
Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" `
-Method POST `
-Headers @{"PRIVATE-TOKEN" = "glpat-token"} `
-Body @{
name = "APK app"
url = "$UPLOAD_URL_APK"
}
- Write-Output "APK added to release successfully."
dependencies:
- create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
- upload_apk
update_aab:
stage: update_files
tags:
- winserver
needs:
- job: upload_aab # Зависимость от upload_wasm
artifacts: true
- create_release
script:
- Write-Output "$UPLOAD_URL_AAB"
- Write-Output "$VERSION_TAG"
- echo "$VERSION_TAG"
- echo "Adding AAB to GitLab Release..."
- echo "Release tag $RELEASE_TAG"
- if (!$RELEASE_TAG) { Write-Error "RELEASE_TAG is missing"; exit 1 }
- $UPLOAD_URL_AAB = $env:UPLOAD_URL_AAB
- if (!$UPLOAD_URL_AAB) { Write-Error "UPLOAD_URL_AAB is missing"; exit 1 }
- |
Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" `
-Method POST `
-Headers @{"PRIVATE-TOKEN" = "glpat-token"} `
-Body @{
name = "AAB app"
url = "$UPLOAD_URL_AAB"
}
- Write-Output "AAB added to release successfully."
dependencies:
- create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
- upload_aab
update_msi:
stage: update_files
tags:
- winserver
needs:
- job: upload_msi # Зависимость от upload_wasm
artifacts: true
- create_release
script:
- Write-Output "$UPLOAD_URL_MSI"
- Write-Output "$VERSION_TAG"
- echo "$VERSION_TAG"
- echo "Adding MSI to GitLab Release..."
- echo "Release tag $RELEASE_TAG"
- if (!$RELEASE_TAG) { Write-Error "RELEASE_TAG is missing"; exit 1 }
- $UPLOAD_URL_MSI = $env:UPLOAD_URL_MSI
- if (!$UPLOAD_URL_MSI) { Write-Error "UPLOAD_URL_MSI is missing"; exit 1 }
- |
Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" `
-Method POST `
-Headers @{"PRIVATE-TOKEN" = "glpat-token"} `
-Body @{
name = "MSI app"
url = "$UPLOAD_URL_MSI"
}
- Write-Output "MSI added to release successfully."
dependencies:
- create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
- upload_msi
# update_wasm:
# stage: update_files
# tags:
# - winserver
# needs:
# - job: upload_wasm # Зависимость от upload_wasm
# artifacts: true
# - create_release
# script:
# - Write-Output "$VERSION_TAG"
# - echo "$VERSION_TAG"
# - echo "Adding WASM to GitLab Release..."
# - echo "Release tag $RELEASE_TAG"
# - if (!$RELEASE_TAG) { Write-Error "RELEASE_TAG is missing"; exit 1 }
# - $UPLOAD_URL_WASM = $env:UPLOAD_URL_WASM
# - if (!$UPLOAD_URL_WASM) { Write-Error "UPLOAD_URL_WASM is missing"; exit 1 }
# - |
# Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" `
# -Method POST `
# -Headers @{"PRIVATE-TOKEN" = "glpat-token"} `
# -Body @{
# name = "WASM app"
# url = "$UPLOAD_URL_WASM"
# }
# - Write-Output "WASM added to release successfully."
# dependencies:
# - create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
# - upload_wasm
update_wasm_on_macos:
stage: update_files
tags:
- macos-mini
needs:
- job: upload_wasm_on_macos # Зависимость от upload_wasm
artifacts: true
- create_release
before_script: []
script:
- echo "$VERSION_TAG"
- echo "Adding WASM to GitLab Release..."
- 'echo "Release tag: $RELEASE_TAG"'
- if [ -z "$RELEASE_TAG" ]; then
echo "RELEASE_TAG is missing" >&2;
exit 1;
fi
- if [ -z "$UPLOAD_URL_WASM" ]; then
echo "UPLOAD_URL_WASM is missing" >&2;
exit 1;
fi
- echo "Uploading WASM link to release..."
- |
curl -s --request POST "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" \
--header "PRIVATE-TOKEN: glpat-token" \
--header "Content-Type: application/json" \
--data "{
\"name\": \"WASM app\",
\"url\": \"$UPLOAD_URL_WASM\"
}"
- echo "WASM added to release successfully."
dependencies:
- create_release
- upload_wasm_on_macos
#update_js:
# stage: update_files
# tags:
# - winserver
# needs:
# - job: upload_js # Зависимость от upload_wasm
# artifacts: true
# - create_release
# script:
# - Write-Output "$VERSION_TAG"
# - echo "$VERSION_TAG"
# - echo "Adding JS to GitLab Release..."
# - echo "Release tag $RELEASE_TAG"
# - if (!$RELEASE_TAG) { Write-Error "RELEASE_TAG is missing"; exit 1 }
# - $UPLOAD_URL_JS = $env:UPLOAD_URL_JS
#
# - if (!$UPLOAD_URL_JS) { Write-Error "UPLOAD_URL_JS is missing"; exit 1 }
# - |
# Invoke-RestMethod -Uri "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" `
# -Method POST `
# -Headers @{"PRIVATE-TOKEN" = "glpat-token"} `
# -Body @{
# name = "JS app"
# url = "$UPLOAD_URL_JS"
# }
# - Write-Output "JS added to release successfully."
# dependencies:
# - create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
# - upload_js
update_js_on_macos:
stage: update_files
tags:
- macos-mini
needs:
- job: upload_js_on_macos # Зависимость от upload_wasm
artifacts: true
- create_release
before_script: [ ]
script:
- echo "$VERSION_TAG"
- echo "Adding JS to GitLab Release..."
- 'echo "Release tag: $RELEASE_TAG"'
- if [ -z "$RELEASE_TAG" ]; then
echo "RELEASE_TAG is missing" >&2;
exit 1;
fi
- if [ -z "$UPLOAD_URL_JS" ]; then
echo "UPLOAD_URL_JS is missing" >&2;
exit 1;
fi
- echo "Uploading JS link to release..."
- |
curl -s --request POST "https://gitlab.example.com/api/v4/projects/*id*/releases/$RELEASE_TAG/assets/links" \
--header "PRIVATE-TOKEN: glpat-token" \
--header "Content-Type: application/json" \
--data "{
\"name\": \"JS app\",
\"url\": \"$UPLOAD_URL_JS\"
}"
- echo "JS added to release successfully."
dependencies:
- create_release # Указываем зависимость от предыдущего джоба, чтобы использовать его артефакты
- upload_js_on_macos
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment