build-package.yaml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. # This automation builds 3p packages based on a PR
  2. name: Build 3P Packages
  3. on:
  4. pull_request:
  5. branches:
  6. - main
  7. - development
  8. paths:
  9. - 'package_build_list_host_*.json'
  10. jobs:
  11. detect-changes:
  12. name: Detecting changes in PR to build
  13. runs-on: ubuntu-latest
  14. outputs:
  15. matrix: ${{ steps.detect-platform.outputs.matrix }}
  16. steps:
  17. - name: Checkout 3P source repo
  18. uses: actions/checkout@v4
  19. with:
  20. fetch-depth: 0
  21. - name: Get package and platform from JSON changes
  22. id: detect-platform
  23. run: |
  24. CHANGED_FILES=$(git diff ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} --name-only)
  25. # Construct the package and os into a json string to be consumed by Github Actions runners
  26. declare -A PACKAGES_JSON
  27. declare -A DOCKERFILE
  28. for FILE in $CHANGED_FILES; do
  29. if [[ $FILE == package_build_list_host_* ]]; then
  30. PLATFORM=$(echo $FILE | sed -n 's/package_build_list_host_\(.*\).json/\1/p')
  31. case $PLATFORM in
  32. linux*)
  33. OS_RUNNER="ubuntu-20.04"
  34. ;;
  35. windows)
  36. OS_RUNNER="windows-latest" # This is bundled with VS2022
  37. ;;
  38. darwin)
  39. OS_RUNNER="macos-13" # Use x86 runner image. Latest uses ARM64
  40. ;;
  41. *)
  42. OS_RUNNER="windows-latest" # default
  43. ;;
  44. esac
  45. # Only get the changes that can be built
  46. IFS=$'\n' # Process each line in the package build file
  47. for LINE in DIFF=$(git diff ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} \
  48. --no-ext-diff --unified=0 \
  49. --exit-code -a --no-prefix -- $FILE | egrep "^\+[^\+]" | egrep -v "^\+\+\+ "); do
  50. unset IFS # Reset IFS to avoid word splitting
  51. PACKAGE=$(echo $LINE | cut -d'"' -f2)
  52. PACKPATH=$(echo $LINE | egrep -o "package-system/[^/ ]+(?=/| )" | head -n 1)
  53. if [[ -z "${DOCKERFILE["$PACKAGE"]}" && -n "$PACKPATH" ]]; then
  54. DOCKER=$(test -e ${PACKPATH%% }/Dockerfile* && echo 1 || echo 0) # Assume the build scripts will use the Dockerfile if found in the package path
  55. DOCKERFILE["$PACKAGE"]=1 # Mark Dockerfile check as done
  56. fi
  57. # Special cases for certain packages
  58. if [[ $PACKAGE =~ "DirectXShaderCompilerDxc" ]] && [[ $PLATFORM =~ "windows" ]]; then
  59. OS_RUNNER="windows-2019"
  60. fi
  61. PACKAGES_JSON["$PACKAGE"]="{\"package\": \"$PACKAGE\", \"os\": \"$OS_RUNNER\", \"dockerfile\": \"$DOCKER\"}"
  62. done
  63. unset IFS
  64. fi
  65. done
  66. # Construct the complete JSON from the array
  67. JSON="{\"include\":["
  68. for PKG_JSON in "${PACKAGES_JSON[@]}"; do
  69. JSON="$JSON$PKG_JSON,"
  70. done
  71. # Remove last "," and add closing brackets
  72. if [[ $JSON == *, ]]; then
  73. JSON="${JSON%?}"
  74. fi
  75. JSON="$JSON]}"
  76. echo $JSON
  77. # Set output
  78. echo "matrix=$( echo "$JSON" )" >> $GITHUB_OUTPUT
  79. validate-changes:
  80. name: Check changes for issues
  81. needs: detect-changes
  82. strategy:
  83. fail-fast: false
  84. matrix: ${{fromJson(needs.detect-changes.outputs.matrix)}}
  85. runs-on: ubuntu-latest
  86. steps:
  87. - name: Checkout 3P source repo
  88. uses: actions/checkout@v4
  89. - name: Check if package already exists in prod
  90. env:
  91. PROD_CDN: ${{ vars.PROD_CDN }} # Change this to compare on your own endpoint
  92. run: |
  93. url="${{ env.PROD_CDN }}/${{ matrix.package }}"
  94. if curl --head --silent --fail ${url}.tar.xz > /dev/null 2>&1; then
  95. echo ${{ matrix.package }} already exists in prod. Check the rev in the json file to ensure it is incremented
  96. exit 1
  97. else
  98. echo ${{ matrix.package }} does not exist in CDN, continuing...
  99. exit 0
  100. fi
  101. - name: Malware scan of repo
  102. uses: dell/common-github-actions/malware-scanner@main
  103. with:
  104. directories: .
  105. options: -r
  106. build-on-specific-os:
  107. name: Build on "${{ matrix.os }}" for "${{ matrix.package }}"
  108. needs: [detect-changes, validate-changes]
  109. strategy:
  110. fail-fast: false
  111. matrix: ${{fromJson(needs.detect-changes.outputs.matrix)}}
  112. runs-on: ${{ matrix.os }}
  113. steps:
  114. - name: Configure
  115. id: configure
  116. run: |
  117. git config --global core.longpaths true
  118. echo "uid_gid=$(id -u):$(id -g)" >> $GITHUB_OUTPUT
  119. - name: Checkout 3P source repo
  120. uses: actions/checkout@v4
  121. with:
  122. path: source
  123. fetch-depth: 0
  124. - name: Checkout 3P scripts repo
  125. uses: actions/checkout@v4
  126. with:
  127. repository: o3de/3p-package-scripts
  128. path: scripts
  129. - name: Update python
  130. uses: actions/setup-python@v4
  131. with:
  132. python-version: '3.10'
  133. cache: 'pip'
  134. - name: Install python dependancies
  135. run: |
  136. python3 -m pip install boto3 certifi
  137. - name: Update cmake/ninja
  138. uses: lukka/get-cmake@latest
  139. - name: Update msbuild path
  140. if: runner.os == 'Windows'
  141. uses: ilammy/[email protected]
  142. - name: Setup NDK
  143. env:
  144. ANDROID_NDK_VERSION: 25.1.8937393
  145. if: runner.os == 'Windows'
  146. run: |
  147. $sdkPath = if ($env:ANDROID_HOME) {
  148. $env:ANDROID_HOME
  149. } else {
  150. "$env:LOCALAPPDATA\Android\Sdk"
  151. }
  152. # Remove versioned NDK directories
  153. if (Test-Path "$sdkPath\ndk") {
  154. Get-ChildItem "$sdkPath\ndk" -Directory |
  155. Where-Object { $_.Name -match '^\d' } |
  156. ForEach-Object {
  157. Remove-Item $_.FullName -Recurse -Force
  158. Write-Host "Removed NDK version: $($_.Name)" -ForegroundColor Green
  159. }
  160. }
  161. # Install NDK version based on ANDROID_NDK_VERSION
  162. if ($env:ANDROID_NDK_VERSION) {
  163. $sdkmanager = "$sdkPath\cmdline-tools\latest\bin\sdkmanager.bat"
  164. if (-not (Test-Path $sdkmanager)) {
  165. $sdkmanager = "$sdkPath\tools\bin\sdkmanager.bat"
  166. }
  167. if (Test-Path $sdkmanager) {
  168. Write-Host "Installing NDK version $env:ANDROID_NDK_VERSION..." -ForegroundColor Yellow
  169. & $sdkmanager --install "ndk;$env:ANDROID_NDK_VERSION" --channel=0
  170. } else {
  171. Write-Host "sdkmanager not found. Cannot install NDK." -ForegroundColor Red
  172. exit 1
  173. }
  174. }
  175. # Set NDK folder path in the env vars
  176. $ndkRoot = "$sdkPath\ndk\$env:ANDROID_NDK_VERSION"
  177. echo ANDROID_NDK=$ndkRoot >> $env:GITHUB_ENV
  178. echo ANDROID_NDK_HOME=$ndkRoot >> $env:GITHUB_ENV
  179. echo ANDROID_NDK_ROOT=$ndkRoot >> $env:GITHUB_ENV
  180. - name: Install clang/gcc
  181. if: runner.os == 'Linux'
  182. env:
  183. CLANG_VER: 12
  184. GCC_VER: 9
  185. run: |
  186. sudo apt-get install -y clang-${{ env.CLANG_VER }} gcc-${{ env.GCC_VER }} g++-${{ env.GCC_VER }}
  187. sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{ env.CLANG_VER }} 10
  188. sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{ env.CLANG_VER }} 10
  189. sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ env.GCC_VER }} 10
  190. sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${{ env.GCC_VER }} 10
  191. - name: Use sccache
  192. uses: hendrikmuhs/[email protected]
  193. with:
  194. variant: sccache
  195. max-size: 2048M
  196. key: ${{ matrix.package }}-${{ matrix.os }}
  197. restore-keys:
  198. ${{ matrix.package }}-${{ matrix.os }}
  199. - name: Set up QEMU (aarch64) # Only if the package folder contains a Dockerfile
  200. if: ${{ (contains(matrix.package, 'aarch64')) && (matrix.dockerfile == '1') }}
  201. run: |
  202. sudo apt-get install -y qemu qemu-user-static
  203. - name: Run build command
  204. if: ${{ (!contains(matrix.package, 'aarch64')) || (matrix.dockerfile == '1') }}
  205. env:
  206. CMAKE_CXX_COMPILER_LAUNCHER: sccache
  207. CMAKE_C_COMPILER_LAUNCHER: sccache
  208. CMAKE_GENERATOR: Ninja # ccache/sccache cannot be used as the compiler launcher under cmake if the generator is MSBuild
  209. run: |
  210. python3 scripts/o3de_package_scripts/build_package.py --search_path source ${{ matrix.package }}
  211. - name: Run build command (aarch64) # Generic build for packages without a Dockerfile
  212. if: ${{ (contains(matrix.package, 'aarch64')) && (matrix.dockerfile != '1') }}
  213. uses: uraimo/[email protected]
  214. with:
  215. arch: none
  216. distro: none
  217. base_image: ghcr.io/${{ github.repository }}/run-on-arch-${{ github.repository_owner }}-${{ github.event.repository.name }}-build-container-aarch64-ubuntu20-04:latest # built from build-container.yaml
  218. setup: |
  219. grep -q ${{ matrix.package }} ${PWD}/source/package_build_list_host_linux.json || rm ${PWD}/source/package_build_list_host_linux.json
  220. dockerRunArgs: |
  221. --platform=linux/arm64
  222. --user ${{ steps.configure.outputs.uid_gid }}
  223. --volume "${PWD}:/workspace"
  224. --volume "${PWD}/scripts:/scripts"
  225. --volume "${PWD}/source:/source"
  226. env: |
  227. CMAKE_CXX_COMPILER_LAUNCHER: sccache
  228. CMAKE_C_COMPILER_LAUNCHER: sccache
  229. SCCACHE_IDLE_TIMEOUT: 0
  230. SCCACHE_DIR: /workspace/.sccache
  231. SCCACHE_CACHE_SIZE: 2048M
  232. shell: /bin/bash
  233. run: |
  234. lsb_release -a
  235. uname -a
  236. sccache --start-server
  237. sccache -z
  238. ls -lah /workspace
  239. python3 /scripts/o3de_package_scripts/build_package.py --search_path /source/ ${{ matrix.package }}
  240. - name: Upload packages
  241. uses: actions/upload-artifact@v4
  242. with:
  243. name: ${{ matrix.package }}
  244. path: source/packages/*
  245. validate-packages:
  246. name: Validating ${{ matrix.package }}
  247. needs: [detect-changes, build-on-specific-os]
  248. runs-on: 'ubuntu-latest'
  249. strategy:
  250. fail-fast: false
  251. matrix: ${{fromJson(needs.detect-changes.outputs.matrix)}}
  252. steps:
  253. - name: Download packages
  254. uses: actions/download-artifact@v4
  255. with:
  256. name: ${{ matrix.package }}
  257. - name: Verify SHA256
  258. run: |
  259. echo "$(cat ${{ matrix.package }}.tar.xz.SHA256SUMS)"
  260. echo "$(cat ${{ matrix.package }}.tar.xz.SHA256SUMS | cut -d" " -f1) ${{ matrix.package }}.tar.xz" | sha256sum --check
  261. - name: Decompress package
  262. if: ${{ !contains(matrix.package, 'aarch64') }}
  263. run: |
  264. tar -xvf ${{ matrix.package }}.tar.xz
  265. - name: Malware scan
  266. uses: dell/common-github-actions/malware-scanner@main
  267. with:
  268. directories: .
  269. options: -r