name: Macos Installer run-name: ${{ inputs.cura_conan_version }} for Macos-${{ inputs.architecture }} by @${{ github.actor }} on: workflow_dispatch: inputs: cura_conan_version: description: 'Cura Conan Version' default: 'cura/latest@ultimaker/testing' required: true type: string conan_args: description: 'Conan args: eq.: --require-override' default: '' required: false type: string enterprise: description: 'Build Cura as an Enterprise edition' default: false required: true type: boolean staging: description: 'Use staging API' default: false required: true type: boolean architecture: description: 'Architecture' required: true default: 'ARM64' type: choice options: - X64 - ARM64 operating_system: description: 'OS' required: true default: 'self-hosted-ARM64' type: choice options: - self-hosted-X64 - self-hosted-ARM64 - macos-11 - macos-12 workflow_call: inputs: cura_conan_version: description: 'Cura Conan Version' default: 'cura/latest@ultimaker/testing' required: true type: string conan_args: description: 'Conan args: eq.: --require-override' default: '' required: false type: string enterprise: description: 'Build Cura as an Enterprise edition' default: false required: true type: boolean staging: description: 'Use staging API' default: false required: true type: boolean architecture: description: 'Architecture' required: true default: 'ARM64' type: string operating_system: description: 'OS' required: true default: 'self-hosted-ARM64' type: string env: CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }} MAC_NOTARIZE_USER: ${{ secrets.MAC_NOTARIZE_USER }} MAC_NOTARIZE_PASS: ${{ secrets.MAC_NOTARIZE_PASS }} MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }} MACOS_CERT_INSTALLER_P12: ${{ secrets.MACOS_CERT_INSTALLER_P12 }} MACOS_CERT_USER: ${{ secrets.MACOS_CERT_USER }} MACOS_CERT_PASSPHRASE: ${{ secrets.MACOS_CERT_PASSPHRASE }} CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }} ENTERPRISE: ${{ inputs.enterprise }} STAGING: ${{ inputs.staging }} jobs: cura-installer-create: runs-on: ${{ inputs.operating_system }} outputs: INSTALLER_FILENAME: ${{ steps.filename.outputs.INSTALLER_FILENAME }} steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Python and pip uses: actions/setup-python@v4 with: python-version: '3.11.x' cache: 'pip' cache-dependency-path: .github/workflows/requirements-conan-package.txt - name: Install Python requirements for runner run: pip install -r .github/workflows/requirements-conan-package.txt - name: Cache Conan local repository packages (Bash) uses: actions/cache@v3 with: path: | $HOME/.conan/data $HOME/.conan/conan_download_cache key: conan-${{ runner.os }}-${{ runner.arch }}-installer-cache - name: Install MacOS system requirements run: brew install cmake autoconf automake ninja create-dmg - name: Create the default Conan profile run: conan profile new default --detect --force - name: Remove Macos keychain (Bash) run: security delete-keychain signing_temp.keychain || true - name: Configure Macos keychain Developer Cert(Bash) id: macos-keychain-developer-cert uses: apple-actions/import-codesign-certs@v1 with: keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} p12-file-base64: ${{ secrets.MACOS_CERT_P12 }} p12-password: ${{ secrets.MACOS_CERT_PASSPHRASE }} - name: Configure Macos keychain Installer Cert (Bash) id: macos-keychain-installer-cert uses: apple-actions/import-codesign-certs@v1 with: keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} create-keychain: false # keychain is created in previous use of action. p12-file-base64: ${{ secrets.MACOS_CERT_INSTALLER_P12 }} p12-password: ${{ secrets.MACOS_CERT_PASSPHRASE }} - name: Remove private Artifactory run: conan remote remove cura-private-conan-dev || true - name: Get Conan configuration run: | conan config install https://github.com/Ultimaker/conan-config.git conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}" - name: Use Conan download cache (Bash) run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache" - name: Create the Packages (Bash) run: conan install $CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$ENTERPRISE -o cura:staging=$STAGING -c tools.build:skip_test=True - name: Remove internal packages before uploading run: | conan remove "*@internal/*" -f || true conan remove "cura_private_data*" -f || true - name: Upload the Package(s) run: | conan upload "*" -r cura --all -c - name: Set Environment variables for Cura (bash) run: | . ./cura_inst/bin/activate_github_actions_env.sh . ./cura_inst/bin/activate_github_actions_version_env.sh - name: Unlock Macos keychain (Bash) run: security unlock -p $TEMP_KEYCHAIN_PASSWORD signing_temp.keychain env: TEMP_KEYCHAIN_PASSWORD: ${{ steps.macos-keychain-developer-cert.outputs.keychain-password }} # FIXME: This is a workaround to ensure that we use and pack a shared library for OpenSSL 1.1.1l. We currently compile # OpenSSL statically for CPython, but our Python Dependenies (such as PyQt6) require a shared library. # Because Conan won't allow for building the same library with two different options (easily) we need to install it explicitly # and do a manual copy to the VirtualEnv, such that Pyinstaller can find it. - name: Install OpenSSL shared run: conan install openssl/1.1.1l@_/_ --build=missing --update -o openssl:shared=True -g deploy - name: Copy OpenSSL shared (Bash) run: | cp ./openssl/lib/*.so* ./cura_inst/bin/ || true cp ./openssl/lib/*.dylib* ./cura_inst/bin/ || true - name: Create the Cura dist run: pyinstaller ./cura_inst/UltiMaker-Cura.spec - name: Output the name file name and extension id: filename shell: python run: | import os enterprise = "-Enterprise" if "${{ inputs.enterprise }}" == "true" else "" installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-${{ inputs.architecture }}" output_env = os.environ["GITHUB_OUTPUT"] content = "" if os.path.exists(output_env): with open(output_env, "r") as f: content = f.read() with open(output_env, "w") as f: f.write(content) f.writelines(f"INSTALLER_FILENAME={installer_filename}\n") - name: Summarize the used dependencies shell: python run: | import os from cura.CuraVersion import ConanInstalls, PythonInstalls summary_env = os.environ["GITHUB_STEP_SUMMARY"] content = "" if os.path.exists(summary_env): with open(summary_env, "r") as f: content = f.read() with open(summary_env, "w") as f: f.write(content) f.writelines("# ${{ steps.filename.outputs.INSTALLER_FILENAME }}\n") f.writelines("## Conan packages:\n") for dep_name, dep_info in ConanInstalls.items(): f.writelines(f"`{dep_name} {dep_info['version']} {dep_info['revision']}`\n") f.writelines("## Python modules:\n") for dep_name, dep_info in PythonInstalls.items(): f.writelines(f"`{dep_name} {dep_info['version']}`\n") - name: Create the Macos dmg (Bash) run: python ../cura_inst/packaging/MacOS/build_macos.py --source_path ../cura_inst --dist_path . --cura_conan_version $CURA_CONAN_VERSION --filename "${{ steps.filename.outputs.INSTALLER_FILENAME }}" --build_dmg --build_pkg --app_name "$CURA_APP_NAME" working-directory: dist - name: Upload the dmg uses: actions/upload-artifact@v3 with: name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-dmg path: | dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.dmg retention-days: 5 - name: Upload the pkg uses: actions/upload-artifact@v3 with: name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-pkg path: | dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.pkg retention-days: 5 - name: Write the run info shell: python run: | import os with open("run_info.sh", "w") as f: f.writelines(f'echo "CURA_VERSION_FULL={os.environ["CURA_VERSION_FULL"]}" >> $GITHUB_ENV\n') - name: Upload the run info uses: actions/upload-artifact@v3 with: name: macos-run-info path: | run_info.sh retention-days: 5 notify-export: if: ${{ always() }} needs: [ cura-installer-create ] uses: ultimaker/cura/.github/workflows/notify.yml@main with: success: ${{ contains(join(needs.*.result, ','), 'success') }} success_title: "Create the Cura distributions" success_body: "Installers for ${{ inputs.cura_conan_version }}" failure_title: "Failed to create the Cura distributions" failure_body: "Failed to create at least 1 installer for ${{ inputs.cura_conan_version }}" secrets: inherit