diff --git a/.github/workflows/conan-package-create.yml b/.github/workflows/conan-package-create.yml deleted file mode 100644 index 56c96f483f..0000000000 --- a/.github/workflows/conan-package-create.yml +++ /dev/null @@ -1,156 +0,0 @@ -name: Create and Upload Conan package - -on: - workflow_call: - inputs: - project_name: - required: true - type: string - - recipe_id_full: - required: true - type: string - - build_id: - required: true - type: number - - build_info: - required: false - default: true - type: boolean - - recipe_id_latest: - required: false - type: string - - runs_on: - required: true - type: string - - python_version: - required: true - type: string - - conan_config_branch: - required: false - type: string - - conan_logging_level: - required: false - type: string - - conan_clean_local_cache: - required: false - type: boolean - default: false - - conan_upload_community: - required: false - default: true - type: boolean - -env: - CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD: ${{ secrets.CONAN_PASS }} - CONAN_LOG_RUN_TO_OUTPUT: 1 - CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }} - CONAN_NON_INTERACTIVE: 1 - -jobs: - conan-package-create: - runs-on: ${{ inputs.runs_on }} - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: ${{ inputs.python_version }} - cache: 'pip' - cache-dependency-path: .github/workflows/requirements-conan-package.txt - - - name: Install Python requirements for runner - run: pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt - # Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo - - - name: Use Conan download cache (Bash) - if: ${{ runner.os != 'Windows' }} - run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache" - - - name: Use Conan download cache (Powershell) - if: ${{ runner.os == 'Windows' }} - run: conan config set storage.download_cache="C:\Users\runneradmin\.conan\conan_download_cache" - - - name: Cache Conan local repository packages (Bash) - uses: actions/cache@v3 - if: ${{ runner.os != 'Windows' }} - with: - path: | - $HOME/.conan/data - $HOME/.conan/conan_download_cache - key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache - - - name: Cache Conan local repository packages (Powershell) - uses: actions/cache@v3 - if: ${{ runner.os == 'Windows' }} - with: - path: | - C:\Users\runneradmin\.conan\data - C:\.conan - C:\Users\runneradmin\.conan\conan_download_cache - key: conan-${{ inputs.runs_on }}-${{ runner.arch }}-create-cache - - - name: Install MacOS system requirements - if: ${{ runner.os == 'Macos' }} - run: brew install autoconf automake ninja - - # NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest. - # This is maybe because grub caches the disk it uses last time, which is recreated each time. - - name: Install Linux system requirements - if: ${{ runner.os == 'Linux' }} - run: | - sudo rm /var/cache/debconf/config.dat - sudo dpkg --configure -a - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt update - sudo apt upgrade - sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison -y - - - name: Install GCC-13 on ubuntu - if: ${{ startsWith(inputs.runs_on, 'ubuntu') }} - run: | - sudo apt install g++-13 gcc-13 -y - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13 - - - name: Create the default Conan profile - run: conan profile new default --detect - - - name: Get Conan configuration from branch - if: ${{ inputs.conan_config_branch != '' }} - run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}" - - - 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: Add Cura private Artifactory remote - run: conan remote add cura-private-conan-dev https://cura.jfrog.io/artifactory/api/conan/cura-private-conan-dev True - - - name: Set GH service account for remote cura-conan-dev - run: conan user -p ${{ secrets.CONAN_GH_RUNNER_PASS }} -r cura-private-conan-dev "${{ secrets.CONAN_GH_RUNNER_USER }}" - - - name: Create the Packages - run: conan install ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True - - - name: Upload the Package(s) - if: ${{ always() && inputs.conan_upload_community }} - run: conan upload ${{ inputs.recipe_id_full }} -r cura --all -c - - - name: Upload the Package(s) to the private Artifactory - if: ${{ always() && ! inputs.conan_upload_community }} - run: conan upload ${{ inputs.recipe_id_full }} -r cura-private-conan-dev --all -c diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 47000752dd..7ca2b0c467 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -1,27 +1,6 @@ ---- name: conan-package -# Exports the recipe, sources and binaries for Mac, Windows and Linux and upload these to the server such that these can -# be used downstream. -# -# It should run on pushes against main or CURA-* branches, but it will only create the binaries for main and release branches - on: - workflow_dispatch: - inputs: - create_binaries_windows: - required: true - default: false - description: 'create binaries Windows' - create_binaries_linux: - required: true - default: false - description: 'create binaries Linux' - create_binaries_macos: - required: true - default: false - description: 'create binaries Macos' - push: paths: - 'plugins/**' @@ -32,15 +11,15 @@ on: - 'packaging/**' - '.github/workflows/conan-*.yml' - '.github/workflows/notify.yml' - - '.github/workflows/requirements-conan-package.txt' + - '.github/workflows/requirements-runner.txt' - 'requirements*.txt' - 'conanfile.py' - 'conandata.yml' - - 'GitVersion.yml' - '*.jinja' branches: - - main + - 'main' - 'CURA-*' + - 'PP-*' - '[0-9].[0-9]' - '[0-9].[0-9][0-9]' tags: @@ -51,95 +30,17 @@ on: env: CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} - CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }} - CONAN_LOG_RUN_TO_OUTPUT: 1 - CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }} - CONAN_NON_INTERACTIVE: 1 -permissions: { } jobs: conan-recipe-version: - permissions: - contents: read - - uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main + uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main with: project_name: cura - conan-package-create-linux: + conan-package-export: needs: [ conan-recipe-version ] - runs-on: 'ubuntu-latest' - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Cache Conan data - id: cache-conan - uses: actions/cache@v3 - with: - path: ~/.conan - key: ${{ runner.os }}-conan - - - 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 - - # NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest. - # This is maybe because grub caches the disk it uses last time, which is recreated each time. - - name: Install Linux system requirements - if: ${{ runner.os == 'Linux' }} - run: | - sudo rm /var/cache/debconf/config.dat - sudo dpkg --configure -a - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt update - sudo apt upgrade - sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison libxcb-cursor-dev g++-12 gcc-12 -y - - - name: Install GCC-13 - run: | - sudo apt install g++-13 gcc-13 -y - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13 - - - name: Create the default Conan profile - run: conan profile new default --detect --force - - - 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: Create the Packages - run: conan create . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o ${{ needs.conan-recipe-version.outputs.project_name }}:devtools=True -o ${{ needs.conan-recipe-version.outputs.project_name }}:enable_i18n=True -c tools.build:skip_test=True - - - name: Create the latest alias - if: always() - run: conan alias ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} ${{ needs.conan-recipe-version.outputs.recipe_id_full }} - - - name: Upload the Package(s) - if: always() - run: | - conan upload ${{ needs.conan-recipe-version.outputs.recipe_id_full }} -r cura --all -c - conan upload ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} -r cura -c - - notify-create: - if: ${{ always() && (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} - needs: [ conan-recipe-version, conan-package-create-linux ] - - uses: ultimaker/cura/.github/workflows/notify.yml@main + uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-export.yml@main with: - success: ${{ contains(join(needs.*.result, ','), 'success') }} - success_title: "New binaries created in ${{ github.repository }}" - success_body: "Created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" - failure_title: "Failed to create binaries in ${{ github.repository }}" - failure_body: "Failed to created binaries for ${{ needs.conan-recipe-version.outputs.recipe_id_full }}" + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }} secrets: inherit diff --git a/.github/workflows/conan-recipe-export.yml b/.github/workflows/conan-recipe-export.yml deleted file mode 100644 index 69c4e4d34a..0000000000 --- a/.github/workflows/conan-recipe-export.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: Export Conan Recipe to server - -on: - workflow_call: - inputs: - recipe_id_full: - required: true - type: string - - recipe_id_latest: - required: false - type: string - - runs_on: - required: true - type: string - - python_version: - required: true - type: string - - conan_config_branch: - required: false - type: string - - conan_logging_level: - required: false - type: string - - conan_export_binaries: - required: false - type: boolean - - conan_upload_community: - required: false - default: true - type: boolean - -env: - CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD: ${{ secrets.CONAN_PASS }} - CONAN_LOG_RUN_TO_OUTPUT: 1 - CONAN_LOGGING_LEVEL: ${{ inputs.conan_logging_level }} - CONAN_NON_INTERACTIVE: 1 - -jobs: - package-export: - runs-on: ${{ inputs.runs_on }} - - steps: - - name: Checkout project - uses: actions/checkout@v3 - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: ${{ inputs.python_version }} - cache: 'pip' - cache-dependency-path: .github/workflows/requirements-conan-package.txt - - - name: Install Python requirements and Create default Conan profile - run: | - pip install -r https://raw.githubusercontent.com/Ultimaker/Cura/main/.github/workflows/requirements-conan-package.txt - conan profile new default --detect - # Note the runner requirements are always installed from the main branch in the Ultimaker/Cura repo - - - name: Cache Conan local repository packages - uses: actions/cache@v3 - with: - path: $HOME/.conan/data - key: ${{ runner.os }}-conan-export-cache - - - name: Get Conan configuration from branch - if: ${{ inputs.conan_config_branch != '' }} - run: conan config install https://github.com/Ultimaker/conan-config.git -a "-b ${{ inputs.conan_config_branch }}" - - - 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: Add Cura private Artifactory remote - run: conan remote add cura-private-conan-dev https://cura.jfrog.io/artifactory/api/conan/cura-private-conan-dev True - - - name: Set GH service account for remote cura-conan-dev - run: conan user -p ${{ secrets.CONAN_GH_RUNNER_PASS }} -r cura-private-conan-dev "${{ secrets.CONAN_GH_RUNNER_USER }}" - - - name: Export the Package (binaries) - if: ${{ inputs.conan_export_binaries }} - run: conan create . ${{ inputs.recipe_id_full }} --build=missing --update -c tools.build:skip_test=True - - - name: Export the Package - if: ${{ !inputs.conan_export_binaries }} - run: conan export . ${{ inputs.recipe_id_full }} - - - name: Create the latest alias - if: always() - run: conan alias ${{ inputs.recipe_id_latest }} ${{ inputs.recipe_id_full }} - - - name: Upload the Package(s) - if: ${{ always() && inputs.conan_upload_community }} - run: | - conan upload ${{ inputs.recipe_id_full }} -r cura --all -c - conan upload ${{ inputs.recipe_id_latest }} -r cura -c - - - name: Upload the Package(s) to the private Artifactory - if: ${{ always() && ! inputs.conan_upload_community }} - run: | - conan upload ${{ inputs.recipe_id_full }} -r cura-private-conan-dev --all -c - conan upload ${{ inputs.recipe_id_latest }} -r cura-private-conan-dev -c diff --git a/.github/workflows/conan-recipe-version.yml b/.github/workflows/conan-recipe-version.yml deleted file mode 100644 index 097b9f5dd6..0000000000 --- a/.github/workflows/conan-recipe-version.yml +++ /dev/null @@ -1,217 +0,0 @@ -name: Get Conan Recipe Version - -on: - workflow_call: - inputs: - project_name: - required: true - type: string - - user: - required: false - default: ultimaker - type: string - - additional_buildmetadata: - required: false - default: "" - type: string - - outputs: - recipe_id_full: - description: "The full Conan recipe id: /@/" - value: ${{ jobs.get-semver.outputs.recipe_id_full }} - - recipe_id_latest: - description: "The full Conan recipe aliased (latest) id: /(latest)@/" - value: ${{ jobs.get-semver.outputs.recipe_id_latest }} - - recipe_semver_full: - description: "The full semver ..-+" - value: ${{ jobs.get-semver.outputs.semver_full }} - - is_release_branch: - description: "is current branch a release branch?" - value: ${{ jobs.get-semver.outputs.release_branch }} - - user: - description: "The conan user" - value: ${{ jobs.get-semver.outputs.user }} - - channel: - description: "The conan channel" - value: ${{ jobs.get-semver.outputs.channel }} - - project_name: - description: "The conan projectname" - value: ${{ inputs.project_name }} - -jobs: - get-semver: - - runs-on: ubuntu-latest - - outputs: - recipe_id_full: ${{ steps.get-conan-broadcast-data.outputs.recipe_id_full }} - recipe_id_latest: ${{ steps.get-conan-broadcast-data.outputs.recipe_id_latest }} - semver_full: ${{ steps.get-conan-broadcast-data.outputs.semver_full }} - is_release_branch: ${{ steps.get-conan-broadcast-data.outputs.is_release_branch }} - user: ${{ steps.get-conan-broadcast-data.outputs.user }} - channel: ${{ steps.get-conan-broadcast-data.outputs.channel }} - - steps: - - name: Checkout repo - uses: actions/checkout@v3 - if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} - with: - fetch-depth: 0 - ref: ${{ github.head_ref }} - - - name: Checkout repo PR - uses: actions/checkout@v3 - if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} - with: - fetch-depth: 0 - ref: ${{ github.base_ref }} - - - 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 and Create default Conan profile - run: | - pip install -r .github/workflows/requirements-conan-package.txt - pip install gitpython - - - id: get-conan-broadcast-data - name: Get Conan broadcast data - run: | - import subprocess - import os - from conan.tools.scm import Version - from conan.errors import ConanException - from git import Repo - - repo = Repo('.') - user = "${{ inputs.user }}".lower() - project_name = "${{ inputs.project_name }}" - event_name = "${{ github.event_name }}" - issue_number = "${{ github.ref }}".split('/')[2] - is_tag = "${{ github.ref_type }}" == "tag" - is_release_branch = False - ref_name = "${{ github.base_ref }}" if event_name == "pull_request" else "${{ github.ref_name }}" - buildmetadata = "" if "${{ inputs.additional_buildmetadata }}" == "" else "${{ inputs.additional_buildmetadata }}_" - - # FIXME: for when we push a tag (such as an release) - channel = "testing" - if is_tag: - branch_version = Version(ref_name) - is_release_branch = True - channel = "_" - user = "_" - actual_version = f"{branch_version}" - else: - try: - branch_version = Version(repo.active_branch.name) - except ConanException: - branch_version = Version('0.0.0') - if ref_name == f"{branch_version.major}.{branch_version.minor}": - channel = 'stable' - is_release_branch = True - elif ref_name in ("main", "master"): - channel = 'testing' - else: - channel = "_".join(repo.active_branch.name.replace("-", "_").split("_")[:2]).lower() - - if "pull_request" in event_name: - channel = f"pr_{issue_number}" - - # %% Get the actual version - latest_branch_version = Version("0.0.0") - latest_branch_tag = None - for tag in repo.active_branch.repo.tags: - if str(tag).startswith("firmware") or str(tag).startswith("master"): - continue # Quick-fix for the versioning scheme name of the embedded team in fdm_materials(_private) repo - try: - version = Version(tag) - except ConanException: - continue - if version > latest_branch_version and version < Version("6.0.0"): - # FIXME: stupid old Cura tags 13.04 etc. keep popping up, als the fdm_material tag for firmware are messing with this - latest_branch_version = version - latest_branch_tag = repo.tag(tag) - - if latest_branch_tag: - # %% Get the actual version - sha_commit = repo.commit().hexsha[:6] - latest_branch_version_prerelease = latest_branch_version.pre - if latest_branch_version.pre and not "." in str(latest_branch_version.pre): - # The prerealese did not contain a version number, default it to 1 - latest_branch_version_prerelease = f"{latest_branch_version.pre}.1" - if event_name == "pull_request": - actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version_prerelease).lower()}+{buildmetadata}pr_{issue_number}_{sha_commit}" - channel_metadata = f"{channel}_{sha_commit}" - else: - if channel in ("stable", "_", ""): - channel_metadata = f"{sha_commit}" - else: - channel_metadata = f"{channel}_{sha_commit}" - if is_release_branch: - if (latest_branch_version.pre == "" or latest_branch_version.pre is None) and branch_version > latest_branch_version: - actual_version = f"{branch_version.major}.{branch_version.minor}.0-beta.1+{buildmetadata}{channel_metadata}" - elif latest_branch_version.pre == "": - # An actual full release has been created, we are working on patch - bump_up_patch = int(str(latest_branch_version.patch)) + 1 - actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{bump_up_patch}-beta.1+{buildmetadata}{channel_metadata}" - elif latest_branch_version.pre is None: - actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{int(latest_branch_version.patch.value) + 1}-beta.1+{buildmetadata}{channel_metadata}" - else: - # An beta release has been created we are working toward a next beta or full release - bump_up_release_tag = int(str(latest_branch_version.pre).split('.')[1]) + 1 - actual_version = f"{latest_branch_version.major}.{latest_branch_version.minor}.{latest_branch_version.patch}-{str(latest_branch_version.pre).split('.')[0]}.{bump_up_release_tag}+{buildmetadata}{channel_metadata}" - else: - max_branches_version = Version("0.0.0") - for branch in repo.references: - try: - if "remotes/origin" in branch.abspath: - b_version = Version(branch.name.split("/")[-1]) - if b_version < Version("6.0.0") and b_version > max_branches_version: - max_branches_version = b_version - except: - pass - if max_branches_version > latest_branch_version: - actual_version = f"{max_branches_version.major}.{int(str(max_branches_version.minor)) + 1}.0-alpha+{buildmetadata}{channel}_{sha_commit}" - else: - actual_version = f"{latest_branch_version.major}.{int(str(latest_branch_version.minor)) + 1}.0-alpha+{buildmetadata}{channel_metadata}" - - # %% Set the environment output - 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"name={project_name}\n") - f.writelines(f"version={actual_version}\n") - f.writelines(f"channel={channel}\n") - f.writelines(f"recipe_id_full={project_name}/{actual_version}@{user}/{channel}\n") - f.writelines(f"recipe_id_latest={project_name}/latest@{user}/{channel}\n") - f.writelines(f"semver_full={actual_version}\n") - f.writelines(f"is_release_branch={str(is_release_branch).lower()}\n") - - summary_env = os.environ["GITHUB_STEP_SUMMARY"] - with open(summary_env, "w") as f: - f.writelines(f"# {project_name}\n") - f.writelines(f"name={project_name}\n") - f.writelines(f"version={actual_version}\n") - f.writelines(f"channel={channel}\n") - f.writelines(f"recipe_id_full={project_name}/{actual_version}@{user}/{channel}\n") - f.writelines(f"recipe_id_latest={project_name}/latest@{user}/{channel}\n") - f.writelines(f"semver_full={actual_version}\n") - f.writelines(f"is_release_branch={str(is_release_branch).lower()}\n") - shell: python diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 38133ad1de..6e531ba833 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -39,56 +39,18 @@ env: CONAN_ARGS: ${{ inputs.conan_args || '' }} ENTERPRISE: ${{ inputs.enterprise || false }} STAGING: ${{ inputs.staging || false }} - LATEST_RELEASE: '5.6' - LATEST_RELEASE_SCHEDULE_HOUR: 4 jobs: default_values: - runs-on: ubuntu-latest - outputs: - cura_conan_version: ${{ steps.default.outputs.cura_conan_version }} - release_tag: ${{ steps.default.outputs.release_tag }} - - steps: - - name: Output default values - id: default - shell: python - run: | - import os - import datetime - - if "${{ github.event_name }}" != "schedule": - cura_conan_version = "${{ github.event.inputs.cura_conan_version }}" - else: - now = datetime.datetime.now() - cura_conan_version = "cura/latest@ultimaker/stable" if now.hour == int(os.environ['LATEST_RELEASE_SCHEDULE_HOUR']) else "cura/latest@ultimaker/testing" - - release_tag = f"nightly-{os.environ['LATEST_RELEASE']}" if "/stable" in cura_conan_version else "nightly" - - # Set cura_conan_version environment variable - 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"cura_conan_version={cura_conan_version}\n") - f.writelines(f"release_tag={release_tag}\n") - - 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(f"# cura_conan_version = {cura_conan_version}\n") - f.writelines(f"# release_tag = {release_tag}\n") + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-default-value.yml@main + with: + cura_conan_version: ${{ inputs.cura_conan_version }} + latest_release: '5.6' + latest_release_schedule_hour: 4 + latest_release_tag: 'nightly' windows-installer: - uses: ./.github/workflows/windows.yml + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} @@ -100,7 +62,7 @@ jobs: secrets: inherit linux-installer: - uses: ./.github/workflows/linux.yml + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} @@ -112,7 +74,7 @@ jobs: secrets: inherit macos-installer: - uses: ./.github/workflows/macos.yml + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} @@ -124,7 +86,7 @@ jobs: secrets: inherit macos-arm-installer: - uses: ./.github/workflows/macos.yml + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main needs: [ default_values ] with: cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }} @@ -142,9 +104,9 @@ jobs: needs: [ default_values, windows-installer, linux-installer, macos-installer, macos-arm-installer ] steps: - name: Checkout - uses: actions/checkout@v3 - - # It's not necessary to download all three, but it does make sure we have at least one if an OS is skipped. + uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Download the run info uses: actions/download-artifact@v2 @@ -193,7 +155,7 @@ jobs: with: name: ${{ steps.filename.outputs.LINUX }}-AppImage path: installers - + - name: Download linux installer jobs asc artifacts uses: actions/download-artifact@v2 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 8b6d892fa0..f88b77a022 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,5 +1,5 @@ name: Linux Installer -run-name: ${{ inputs.cura_conan_version }} for Linux-${{ inputs.architecture }} by @${{ github.actor }} +run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }} on: workflow_dispatch: @@ -39,219 +39,19 @@ on: options: - ubuntu-22.04 - 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: 'X64' - type: string - operating_system: - description: 'OS' - required: true - default: 'ubuntu-22.04' - type: string - env: - CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} - GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} - CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }} - ENTERPRISE: ${{ inputs.enterprise }} - STAGING: ${{ inputs.staging }} + CONAN_ARGS: ${{ inputs.conan_args || '' }} + ENTERPRISE: ${{ inputs.enterprise || false }} + STAGING: ${{ inputs.staging || false }} jobs: - cura-installer-create: - runs-on: ${{ inputs.operating_system }} - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: '3.10.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 Linux system requirements - run: | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt update - sudo apt upgrade - sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config binutils coreutils desktop-file-utils fakeroot fuse libgdk-pixbuf2.0-dev patchelf squashfs-tools strace util-linux zsync libxcb-cursor-dev -y - - # Get the AppImage tool - wget --no-check-certificate --quiet https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O $GITHUB_WORKSPACE/appimagetool - chmod +x $GITHUB_WORKSPACE/appimagetool - echo "APPIMAGETOOL_LOCATION=$GITHUB_WORKSPACE/appimagetool" >> $GITHUB_ENV - - # Get the AppImage builder - wget --no-check-certificate --quiet -O $GITHUB_WORKSPACE/appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage - chmod +x appimage-builder-x86_64.AppImage - echo "APPIMAGEBUILDER_LOCATION=$GITHUB_WORKSPACE/appimage-builder-x86_64.AppImage" >> $GITHUB_ENV - - # Make sure these tools can be found on the path - echo "$GITHUB_WORKSPACE" >> $GITHUB_PATH - - - name: Install GCC-13 - run: | - sudo apt install g++-13 gcc-13 -y - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13 - - - name: Create the default Conan profile - run: conan profile new default --detect --force - - - name: Configure GPG Key Linux (Bash) - run: echo -n "$GPG_PRIVATE_KEY" | base64 --decode | gpg --import - - - 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) - if: always() - 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: 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}-linux-${{ 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 Linux AppImage (Bash) - run: | - python ../cura_inst/packaging/AppImage-builder/create_appimage.py ./UltiMaker-Cura $CURA_VERSION_FULL "${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage" - chmod +x "${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage" - working-directory: dist - - - name: Upload the AppImage - uses: actions/upload-artifact@v3 - with: - name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-AppImage - path: | - dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage - retention-days: 5 - - - name: Upload the asc - uses: actions/upload-artifact@v3 - with: - name: ${{ steps.filename.outputs.INSTALLER_FILENAME }}-asc - path: | - dist/${{ steps.filename.outputs.INSTALLER_FILENAME }}.AppImage.asc - 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: linux-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 + installer: + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.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 + cura_conan_version: ${{ inputs.cura_conan_version }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise == 'true' }} + staging: ${{ inputs.staging == 'true' }} + architecture: ${{ inputs.architecture }} + operating_system: ${{ inputs.operating_system }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c7c34d9d51..e909b9f839 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,5 +1,5 @@ -name: Macos Installer -run-name: ${{ inputs.cura_conan_version }} for Macos-${{ inputs.architecture }} by @${{ github.actor }} +name: MacOS Installer +run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }} on: workflow_dispatch: @@ -42,229 +42,20 @@ on: - 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 }} + CONAN_ARGS: ${{ inputs.conan_args || '' }} + ENTERPRISE: ${{ inputs.enterprise || false }} + STAGING: ${{ inputs.staging || false }} 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 }} - - - 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 + installer: + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.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 + cura_conan_version: ${{ inputs.cura_conan_version }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise == 'true' }} + staging: ${{ inputs.staging == 'true' }} + architecture: ${{ inputs.architecture }} + operating_system: ${{ inputs.operating_system }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/notify.yml b/.github/workflows/notify.yml deleted file mode 100644 index 370b54c78b..0000000000 --- a/.github/workflows/notify.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Get Conan Recipe Version - -on: - workflow_call: - inputs: - success: - required: true - type: boolean - - success_title: - required: true - type: string - - success_body: - required: true - type: string - - failure_title: - required: true - type: string - - failure_body: - required: true - type: string - - -jobs: - slackNotification: - name: Slack Notification - - runs-on: ubuntu-latest - - steps: - - name: Slack notify on-success - if: ${{ inputs.success }} - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_USERNAME: ${{ github.repository }} - SLACK_COLOR: green - SLACK_ICON: https://github.com/Ultimaker/Cura/blob/main/icons/cura-128.png?raw=true - SLACK_TITLE: ${{ inputs.success_title }} - SLACK_MESSAGE: ${{ inputs.success_body }} - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - - - name: Slack notify on-failure - if: ${{ !inputs.success }} - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_USERNAME: ${{ github.repository }} - SLACK_COLOR: red - SLACK_ICON: https://github.com/Ultimaker/Cura/blob/main/icons/cura-128.png?raw=true - SLACK_TITLE: ${{ inputs.failure_title }} - SLACK_MESSAGE: ${{ inputs.failure_body }} - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/process-pull-request.yml b/.github/workflows/process-pull-request.yml index 7fe3aedc96..45b3f8c915 100644 --- a/.github/workflows/process-pull-request.yml +++ b/.github/workflows/process-pull-request.yml @@ -1,15 +1,10 @@ name: process-pull-request on: - pull_request_target: - types: [opened, reopened, edited, synchronize, review_requested, ready_for_review, assigned] + pull_request_target: + types: [ opened, reopened, edited, review_requested, ready_for_review, assigned ] jobs: - add_label: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-ecosystem/action-add-labels@v1 - if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} - with: - labels: 'PR: Community Contribution :crown:' \ No newline at end of file + add_label: + uses: ultimaker/cura-workflows/.github/workflows/process-pull-request.yml@main + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/requirements-runner.txt b/.github/workflows/requirements-runner.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/workflows/unit-test-post.yml b/.github/workflows/unit-test-post.yml index 36c1d5acfd..eaf69692a7 100644 --- a/.github/workflows/unit-test-post.yml +++ b/.github/workflows/unit-test-post.yml @@ -1,82 +1,13 @@ name: unit-test-post on: - workflow_run: - workflows: [ "unit-test" ] - types: [ completed ] + workflow_run: + workflows: [ "unit-test" ] + types: [ completed ] jobs: - publish-test-results: - if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} - runs-on: ubuntu-latest - - steps: - - name: Download analysis results - uses: actions/github-script@v3.1.0 - with: - script: | - let artifacts = await github.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: ${{github.event.workflow_run.id }}, - }); - let matchArtifact = artifacts.data.artifacts.filter((artifact) => { - return artifact.name == "test-result" - })[0]; - let download = await github.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: "zip", - }); - let fs = require("fs"); - fs.writeFileSync("${{github.workspace}}/test-result.zip", Buffer.from(download.data)); - - - name: Set environment variables - run: | - mkdir pr_env - unzip test-result.zip -d pr_env - echo "pr_id=$(cat pr_env/pr-id.txt)" >> $GITHUB_ENV - echo "pr_head_repo=$(cat pr_env/pr-head-repo.txt)" >> $GITHUB_ENV - echo "pr_head_ref=$(cat pr_env/pr-head-ref.txt)" >> $GITHUB_ENV - - - uses: actions/checkout@v3 - with: - repository: ${{ env.pr_head_repo }} - ref: ${{ env.pr_head_ref }} - persist-credentials: false - - - name: Redownload analysis results - uses: actions/github-script@v3.1.0 - with: - script: | - let artifacts = await github.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: ${{github.event.workflow_run.id }}, - }); - let matchArtifact = artifacts.data.artifacts.filter((artifact) => { - return artifact.name == "test-result" - })[0]; - let download = await github.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: "zip", - }); - let fs = require("fs"); - fs.writeFileSync("${{github.workspace}}/test-result.zip", Buffer.from(download.data)); - - - name: Extract analysis results - run: | - mkdir -p tests - unzip test-result.zip -d tests - - - name: Publish Unit Test Results - id: test-results - uses: EnricoMi/publish-unit-test-result-action@v1 - with: - files: "tests/**/*.xml" - - - name: Conclusion - run: echo "Conclusion is ${{ steps.test-results.outputs.json && fromJSON( steps.test-results.outputs.json ).conclusion }}" + publish-test-results: + uses: ultimaker/cura-workflows/.github/workflows/unit-test-post.yml@main + with: + event: ${{ github.event.workflow_run.event }} + conclusion: ${{ github.event.workflow_run.conclusion }} diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 8321f42a23..7c6910b39f 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -1,4 +1,3 @@ ---- name: unit-test on: @@ -9,23 +8,18 @@ on: - 'cura/**' - 'icons/**' - 'tests/**' - - 'packaging/**' - - '.github/workflows/conan-*.yml' - '.github/workflows/unit-test.yml' - - '.github/workflows/notify.yml' - - '.github/workflows/requirements-conan-package.txt' + - '.github/workflows/requirements-runner.txt' - 'requirements*.txt' - 'conanfile.py' - 'conandata.yml' - - 'GitVersion.yml' - '*.jinja' branches: - main - 'CURA-*' - - '[1-9]+.[0-9]+' - tags: - - '[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+-beta' + - 'PP-*' + - '[0-9]+.[0-9]+' + pull_request: paths: - 'plugins/**' @@ -33,134 +27,35 @@ on: - 'cura/**' - 'icons/**' - 'tests/**' - - 'packaging/**' - - '.github/workflows/conan-*.yml' - '.github/workflows/unit-test.yml' - - '.github/workflows/notify.yml' - - '.github/workflows/requirements-conan-package.txt' + - '.github/workflows/requirements-runner.txt' - 'requirements*.txt' - 'conanfile.py' - 'conandata.yml' - - 'GitVersion.yml' - '*.jinja' branches: - main - - '[1-9]+.[0-9]+' - tags: - - '[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+-beta' - -env: - CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} - CONAN_LOGIN_USERNAME_CURA_CE: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD_CURA_CE: ${{ secrets.CONAN_PASS }} - CONAN_LOG_RUN_TO_OUTPUT: 1 - CONAN_LOGGING_LEVEL: info - CONAN_NON_INTERACTIVE: 1 + - '[0-9]+.[0-9]+' permissions: contents: read +env: + CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }} + CONAN_PASSWORD: ${{ secrets.CONAN_PASS }} + jobs: conan-recipe-version: - uses: ultimaker/cura/.github/workflows/conan-recipe-version.yml@main + uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main with: project_name: cura testing: - runs-on: ubuntu-22.04 + uses: ultimaker/cura-workflows/.github/workflows/unit-test.yml@main needs: [ conan-recipe-version ] - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 2 - - - name: Setup Python and pip - uses: actions/setup-python@v4 - with: - python-version: '3.11.x' - architecture: 'x64' - cache: 'pip' - cache-dependency-path: .github/workflows/requirements-conan-package.txt - - - name: Install Python requirements and Create default Conan profile - run: pip install -r requirements-conan-package.txt - working-directory: .github/workflows/ - - - name: Use Conan download cache (Bash) - if: ${{ runner.os != 'Windows' }} - run: conan config set storage.download_cache="$HOME/.conan/conan_download_cache" - - - name: Cache Conan local repository packages (Bash) - uses: actions/cache@v3 - if: ${{ runner.os != 'Windows' }} - with: - path: | - $HOME/.conan/data - $HOME/.conan/conan_download_cache - key: conan-${{ runner.os }}-${{ runner.arch }}-unit-cache - - # NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest. - # This is maybe because grub caches the disk it uses last time, which is recreated each time. - - name: Install Linux system requirements - if: ${{ runner.os == 'Linux' }} - run: | - sudo rm /var/cache/debconf/config.dat - sudo dpkg --configure -a - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt update - sudo apt upgrade - sudo apt install build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config -y - - - name: Install GCC-13 - run: | - sudo apt install g++-13 gcc-13 -y - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13 - - - 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: Get Conan profile - run: conan profile new default --detect --force - - - name: Install dependencies - run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} --build=missing --update -o cura:devtools=True -g VirtualPythonEnv -if venv - - - name: Upload the Dependency package(s) - run: conan upload "*" -r cura --all -c - - - name: Set Environment variables for Cura (bash) - if: ${{ runner.os != 'Windows' }} - run: | - . ./venv/bin/activate_github_actions_env.sh - - - name: Run Unit Test - id: run-test - run: | - pytest --junitxml=junit_cura.xml - working-directory: tests - - - name: Save PR metadata - if: always() - run: | - echo ${{ github.event.number }} > pr-id.txt - echo ${{ github.event.pull_request.head.repo.full_name }} > pr-head-repo.txt - echo ${{ github.event.pull_request.head.ref }} > pr-head-ref.txt - working-directory: tests - - - name: Upload Test Results - if: always() - uses: actions/upload-artifact@v3 - with: - name: test-result - path: | - tests/**/*.xml - tests/pr-id.txt - tests/pr-head-repo.txt - tests/pr-head-ref.txt + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + conan_extra_args: '-g VirtualPythonEnv -o cura:devtools=True -c tools.build:skip_test=False' + unit_test_cmd: 'pytest --junitxml=junit_cura.xml' + unit_test_dir: 'tests' + conan_generator_dir: './venv/bin' \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index dfffc4540b..151935c3f3 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,5 +1,5 @@ name: Windows Installer -run-name: ${{ inputs.cura_conan_version }} for Windows-${{ inputs.architecture }} by @${{ github.actor }} +run-name: ${{ inputs.cura_conan_version }} by @${{ github.actor }} on: workflow_dispatch: @@ -38,227 +38,20 @@ on: type: choice options: - windows-2022 - 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: 'X64' - type: string - operating_system: - description: 'OS' - required: true - default: 'windows-2022' - type: string env: - CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }} - CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }} - WIN_CERT_INSTALLER_CER: ${{ secrets.WIN_CERT_INSTALLER_CER }} - WIN_CERT_INSTALLER_CER_PASS: ${{ secrets.WIN_CERT_INSTALLER_CER_PASS }} - CURA_CONAN_VERSION: ${{ inputs.cura_conan_version }} - ENTERPRISE: ${{ inputs.enterprise }} - STAGING: ${{ inputs.staging }} + CONAN_ARGS: ${{ inputs.conan_args || '' }} + ENTERPRISE: ${{ inputs.enterprise || false }} + STAGING: ${{ inputs.staging || false }} 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.10.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 (Powershell) - uses: actions/cache@v3 - with: - path: | - C:\Users\runneradmin\.conan\data - C:\.conan - C:\Users\runneradmin\.conan\conan_download_cache - key: conan-${{ runner.os }}-${{ runner.arch }}-installer-cache - - - name: Create the default Conan profile - run: conan profile new default --detect --force - - - 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 (Powershell) - run: conan config set storage.download_cache="C:\Users\runneradmin\.conan\conan_download_cache" - - - name: Create the Packages (Powershell) - run: conan install $Env:CURA_CONAN_VERSION ${{ inputs.conan_args }} --build=missing --update -if cura_inst -g VirtualPythonEnv -o cura:enterprise=$Env:ENTERPRISE -o cura:staging=$Env: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) - if: always() - run: | - conan upload "*" -r cura --all -c - - - name: Set Environment variables for Cura (Powershell) - run: | - echo "${Env:WIX}\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - .\cura_inst\Scripts\activate_github_actions_env.ps1 - .\cura_inst\Scripts\activate_github_actions_version_env.ps1 - - - 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}-win64-${{ 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 PFX certificate from BASE64_PFX_CONTENT secret - id: create-pfx - env: - PFX_CONTENT: ${{ secrets.WIN_CERT_INSTALLER_CER }} - run: | - $pfxPath = Join-Path -Path $env:RUNNER_TEMP -ChildPath "cert.pfx"; - $encodedBytes = [System.Convert]::FromBase64String($env:PFX_CONTENT); - Set-Content $pfxPath -Value $encodedBytes -AsByteStream; - echo "PFX_PATH=$pfxPath" >> $env:GITHUB_OUTPUT; - - - name: Create the Windows msi installer (Powershell) - run: | - python ..\cura_inst\packaging\msi\create_windows_msi.py ..\cura_inst .\UltiMaker-Cura "${{steps.filename.outputs.INSTALLER_FILENAME }}.msi" "$Env:CURA_APP_NAME" - working-directory: dist - - - name: Sign the Windows msi installer (Powershell) - env: - PFX_PATH: ${{ steps.create-pfx.outputs.PFX_PATH }} - run: | - & "C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe" sign /f $Env:PFX_PATH /p "$Env:WIN_CERT_INSTALLER_CER_PASS" /fd SHA256 /t http://timestamp.digicert.com "${{steps.filename.outputs.INSTALLER_FILENAME }}.msi" - working-directory: dist - - - name: Create the Windows exe installer (Powershell) - run: | - python ..\cura_inst\packaging\NSIS\create_windows_installer.py ../cura_inst . "${{steps.filename.outputs.INSTALLER_FILENAME }}.exe" - working-directory: dist - - - name: Sign the Windows exe installer (Powershell) - env: - PFX_PATH: ${{ steps.create-pfx.outputs.PFX_PATH }} - run: | - & "C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe" sign /f $Env:PFX_PATH /p "$Env:WIN_CERT_INSTALLER_CER_PASS" /fd SHA256 /t http://timestamp.digicert.com "${{steps.filename.outputs.INSTALLER_FILENAME }}.exe" - working-directory: dist - - - name: Upload the msi - uses: actions/upload-artifact@v3 - with: - name: ${{steps.filename.outputs.INSTALLER_FILENAME }}-msi - path: | - dist/${{steps.filename.outputs.INSTALLER_FILENAME }}.msi - retention-days: 5 - - - name: Upload the exe - uses: actions/upload-artifact@v3 - with: - name: ${{steps.filename.outputs.INSTALLER_FILENAME }}-exe - path: | - dist/${{steps.filename.outputs.INSTALLER_FILENAME }}.exe - retention-days: 5 - - # NOTE: The extension is .sh, since this isn't going to build-environment, so not on the Win build image. - - 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') - - # NOTE: The extension is .sh, since this isn't going to build-environment, so not on the Win build image. - - name: Upload the run info - uses: actions/upload-artifact@v3 - with: - name: windows-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 + installer: + uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.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 + cura_conan_version: ${{ inputs.cura_conan_version }} + conan_args: ${{ inputs.conan_args }} + enterprise: ${{ inputs.enterprise == 'true' }} + staging: ${{ inputs.staging == 'true' }} + architecture: ${{ inputs.architecture }} + operating_system: ${{ inputs.operating_system }} + secrets: inherit \ No newline at end of file diff --git a/conandata.yml b/conandata.yml index c027bde567..a0a5a204ca 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,3 +1,18 @@ +version: "5.7.0-alpha.0" +requirements: + - "uranium/(latest)@ultimaker/testing" + - "curaengine/(latest)@ultimaker/testing" + - "cura_binary_data/(latest)@ultimaker/testing" + - "fdm_materials/(latest)@ultimaker/testing" + - "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable" + - "dulcificum/latest@ultimaker/testing" + - "pyarcus/5.3.0" + - "pysavitar/5.3.0" + - "pynest2d/5.3.0" + - "curaengine_grpc_definitions/(latest)@ultimaker/testing" +requirements_internal: + - "fdm_materials/(latest)@internal/testing" + - "cura_private_data/(latest)@internal/testing" urls: default: cloud_api_root: "https://api.ultimaker.com" diff --git a/conanfile.py b/conanfile.py index 4a5201edb7..a3ca8f1c89 100644 --- a/conanfile.py +++ b/conanfile.py @@ -4,7 +4,7 @@ from pathlib import Path from jinja2 import Template from conan import ConanFile -from conan.tools.files import copy, rmdir, save, mkdir, rm +from conan.tools.files import copy, rmdir, save, mkdir, rm, update_conandata from conan.tools.microsoft import unix_path from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv from conan.tools.scm import Version @@ -34,7 +34,7 @@ class CuraConan(ConanFile): "cloud_api_version": "ANY", "display_name": "ANY", # TODO: should this be an option?? "cura_debug_mode": [True, False], # FIXME: Use profiles - "internal": [True, False], + "internal": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string "enable_i18n": [True, False], } default_options = { @@ -44,13 +44,13 @@ class CuraConan(ConanFile): "cloud_api_version": "1", "display_name": "UltiMaker Cura", "cura_debug_mode": False, # Not yet implemented - "internal": False, + "internal": "False", "enable_i18n": False, } def set_version(self): if not self.version: - self.version = "5.7.0-alpha" + self.version = self.conan_data["version"] @property def _i18n_options(self): @@ -72,7 +72,7 @@ class CuraConan(ConanFile): self._cura_env.define("QML2_IMPORT_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "qml"))) self._cura_env.define("QT_PLUGIN_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "plugins"))) if not self.in_local_cache: - self._cura_env.define( "CURA_DATA_ROOT", str(self._share_dir.joinpath("cura"))) + self._cura_env.define("CURA_DATA_ROOT", str(self._share_dir.joinpath("cura"))) if self.settings.os == "Linux": self._cura_env.define("QT_QPA_FONTDIR", "/usr/share/fonts") @@ -84,6 +84,10 @@ class CuraConan(ConanFile): def _enterprise(self): return self.options.enterprise in ["True", 'true'] + @property + def _internal(self): + return self.options.internal in ["True", 'true'] + @property def _app_name(self): if self._enterprise: @@ -182,7 +186,7 @@ class CuraConan(ConanFile): cura_version = Version(self.conf.get("user.cura:version", default = self.version, check_type = str)) pre_tag = f"-{cura_version.pre}" if cura_version.pre else "" build_tag = f"+{cura_version.build}" if cura_version.build else "" - internal_tag = f"+internal" if self.options.internal else "" + internal_tag = f"+internal" if self._internal else "" cura_version = f"{cura_version.major}.{cura_version.minor}.{cura_version.patch}{pre_tag}{build_tag}{internal_tag}" with open(os.path.join(location, "CuraVersion.py"), "w") as f: @@ -206,7 +210,7 @@ class CuraConan(ConanFile): pyinstaller_metadata = self.conan_data["pyinstaller"] datas = [] for data in pyinstaller_metadata["datas"].values(): - if not self.options.internal and data.get("internal", False): + if not self._internal and data.get("internal", False): continue if "package" in data: # get the paths from conan package @@ -238,7 +242,7 @@ class CuraConan(ConanFile): self.output.warning(f"Source path for binary {binary['binary']} does not exist") continue - for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.]*"): + for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.|.pdb]*"): binaries.append((str(bin), binary["dst"])) for bin in Path(src_path).glob(binary["binary"]): binaries.append((str(bin), binary["dst"])) @@ -285,6 +289,9 @@ class CuraConan(ConanFile): short_version = f"'{cura_version.major}.{cura_version.minor}.{cura_version.patch}'", )) + def export(self): + update_conandata(self, {"version": self.version}) + def export_sources(self): copy(self, "*", os.path.join(self.recipe_folder, "plugins"), os.path.join(self.export_sources_folder, "plugins")) copy(self, "*", os.path.join(self.recipe_folder, "resources"), os.path.join(self.export_sources_folder, "resources"), excludes = "*.mo") @@ -311,6 +318,8 @@ class CuraConan(ConanFile): if self.settings.os == "Linux": self.options["curaengine_grpc_definitions"].shared = True self.options["openssl"].shared = True + if self.conf.get("user.curaengine:sentry_url", "", check_type=str) != "": + self.options["curaengine"].enable_sentry = True def validate(self): version = self.conf.get("user.cura:version", default = self.version, check_type = str) @@ -318,26 +327,19 @@ class CuraConan(ConanFile): raise ConanInvalidConfiguration("Only versions 5+ are support") def requirements(self): + for req in self.conan_data["requirements"]: + if self._internal and "fdm_materials" in req: + continue + self.requires(req) + if self._internal: + for req in self.conan_data["requirements_internal"]: + self.requires(req) + self.requires("cpython/3.10.4@ultimaker/stable") + self.requires("openssl/3.2.0") self.requires("boost/1.82.0") self.requires("spdlog/1.12.0") self.requires("fmt/10.1.1") - self.requires("curaengine_grpc_definitions/0.1.0") self.requires("zlib/1.2.13") - self.requires("pyarcus/5.3.0") - self.requires("dulcificum/0.1.0-beta.2") - self.requires("curaengine/(latest)@ultimaker/testing") - self.requires("pysavitar/5.3.0") - self.requires("pynest2d/5.3.0") - self.requires("curaengine_plugin_gradual_flow/0.1.0") - self.requires("uranium/(latest)@ultimaker/testing") - self.requires("cura_binary_data/(latest)@ultimaker/testing") - self.requires("cpython/3.10.4@ultimaker/stable") - self.requires("openssl/3.2.0") - if self.options.internal: - self.requires("cura_private_data/(latest)@internal/testing") - self.requires("fdm_materials/(latest)@internal/testing") - else: - self.requires("fdm_materials/(latest)@ultimaker/testing") def build_requirements(self): if self.options.get_safe("enable_i18n", False): @@ -397,7 +399,7 @@ class CuraConan(ConanFile): copy(self, "*", fdm_materials.resdirs[0], self.source_folder) # Copy internal resources - if self.options.internal: + if self._internal: cura_private_data = self.dependencies["cura_private_data"].cpp_info copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura"))) @@ -516,6 +518,7 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV del self.info.options.cloud_api_version del self.info.options.display_name del self.info.options.cura_debug_mode + self.options.rm_safe("enable_i18n") # TODO: Use the hash of requirements.txt and requirements-ultimaker.txt, Because changing these will actually result in a different # Cura. This is needed because the requirements.txt aren't managed by Conan and therefor not resolved in the package_id. This isn't diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index f3c5f3a1a9..13778e9de9 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -241,14 +241,8 @@ class GridArrange(Arranger): center_grid_x = coord_grid_x + (0.5 * self._grid_width) center_grid_y = coord_grid_y + (0.5 * self._grid_height) - bounding_box = node.getBoundingBox() - center_node_x = (bounding_box.left + bounding_box.right) * 0.5 - center_node_y = (bounding_box.back + bounding_box.front) * 0.5 - - delta_x = center_grid_x - center_node_x - delta_y = center_grid_y - center_node_y - - return TranslateOperation(node, Vector(delta_x, 0, delta_y)) + return TranslateOperation(node, Vector(center_grid_x, node.getWorldPosition().y, center_grid_y), + set_position=True) def _getGridCornerPoints( self, diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c6c44cf8f5..28dfd5e1c9 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -179,6 +179,7 @@ class CuraApplication(QtApplication): self._use_single_instance = False self._single_instance = None + self._open_project_mode: Optional[str] = None self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions] @@ -1845,7 +1846,7 @@ class CuraApplication(QtApplication): Logger.log("i", "Attempting to read file %s", file.toString()) if not file.isValid(): return - + self._open_project_mode = project_mode scene = self.getController().getScene() for node in DepthFirstIterator(scene.getRoot()): @@ -1855,16 +1856,16 @@ class CuraApplication(QtApplication): is_project_file = self.checkIsValidProjectFile(file) - if project_mode is None: - project_mode = self.getPreferences().getValue("cura/choice_on_open_project") + if self._open_project_mode is None: + self._open_project_mode = self.getPreferences().getValue("cura/choice_on_open_project") - if is_project_file and project_mode == "open_as_project": + if is_project_file and self._open_project_mode == "open_as_project": # open as project immediately without presenting a dialog workspace_handler = self.getWorkspaceFileHandler() workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files) return - if is_project_file and project_mode == "always_ask": + if is_project_file and self._open_project_mode == "always_ask": # present a dialog asking to open as project or import models self.callLater(self.openProjectFile.emit, file, add_to_recent_files) return @@ -1999,8 +2000,11 @@ class CuraApplication(QtApplication): center_y = 0 node.translate(Vector(0, center_y, 0)) - nodes_to_arrange.append(node) + # If the file is a project,and models are to be loaded from a that project, + # models inside file should be arranged in buildplate. + elif self._open_project_mode == "open_as_model": + nodes_to_arrange.append(node) # This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy # of BuildPlateDecorator produces one that's associated with build plate -1. So, here we need to check if diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index 103703e594..e5fd307dc9 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -1,5 +1,6 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import math import numpy from typing import Optional, cast @@ -186,6 +187,11 @@ class LayerPolygon: def types(self): return self._types + @property + def lineLengths(self): + data_array = numpy.array(self._data) + return numpy.linalg.norm(data_array[1:] - data_array[:-1], axis=1) + @property def data(self): return self._data diff --git a/cura/PrinterOutput/Models/MaterialOutputModel.py b/cura/PrinterOutput/Models/MaterialOutputModel.py index 6920cead1b..dedcc2136b 100644 --- a/cura/PrinterOutput/Models/MaterialOutputModel.py +++ b/cura/PrinterOutput/Models/MaterialOutputModel.py @@ -43,7 +43,7 @@ class MaterialOutputModel(QObject): } - if guid is None and brand is not "empty" and type in _MATERIAL_MAP: + if guid is None and brand != "empty" and type in _MATERIAL_MAP: name = _MATERIAL_MAP[type]["name"] guid = _MATERIAL_MAP[type]["guid"] return name, guid diff --git a/cura/Snapshot.py b/cura/Snapshot.py index 40c74c9693..f94b3ff42e 100644 --- a/cura/Snapshot.py +++ b/cura/Snapshot.py @@ -49,7 +49,7 @@ class Snapshot: """ if node is None: - root = Application.getInstance().getController().getScene().getRoot() + node = Application.getInstance().getController().getScene().getRoot() # the direction the camera is looking at to create the isometric view iso_view_dir = Vector(-1, -1, -1).normalized() diff --git a/packaging/AppImage-builder/AppImageBuilder.yml.jinja b/packaging/AppImage-builder/AppImageBuilder.yml.jinja index 446c0dacc0..9090a5f209 100644 --- a/packaging/AppImage-builder/AppImageBuilder.yml.jinja +++ b/packaging/AppImage-builder/AppImageBuilder.yml.jinja @@ -38,6 +38,7 @@ AppDir: - usr/share/doc/*/changelog.* - usr/share/doc/*/NEWS.* - usr/share/doc/*/TODO.* + - usr/lib/x86_64-linux-gnu/libssl.so* runtime: env: APPDIR_LIBRARY_PATH: "$APPDIR:$APPDIR/runtime/compat/:$APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders" diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 54c322fa0a..9593b83528 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -33,6 +33,8 @@ message Slice repeated Extruder extruders = 3; // The settings sent to each extruder object repeated SettingExtruder limit_to_extruder = 4; // From which stack the setting would inherit if not defined per object repeated EnginePlugin engine_plugins = 5; + string sentry_id = 6; // The anonymized Sentry user id that requested the slice + string cura_version = 7; // The version of Cura that requested the slice } message Extruder diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 1e965f5e8c..818766d766 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -163,6 +163,7 @@ class CuraEngineBackend(QObject, Backend): self._is_disabled: bool = False application.getPreferences().addPreference("general/auto_slice", False) + application.getPreferences().addPreference("info/send_engine_crash", True) self._use_timer: bool = False @@ -173,6 +174,8 @@ class CuraEngineBackend(QObject, Backend): self._change_timer.setSingleShot(True) self._change_timer.setInterval(500) self.determineAutoSlicing() + + application.getPreferences().preferenceChanged.connect(self._onPreferencesChanged) self._slicing_error_message = Message( @@ -193,6 +196,9 @@ class CuraEngineBackend(QObject, Backend): application.initializationFinished.connect(self.initialize) + # Ensure that the initial value for send_engine_crash is handled correctly. + application.callLater(self._onPreferencesChanged, "info/send_engine_crash") + def startPlugins(self) -> None: """ Ensure that all backend plugins are started @@ -1088,11 +1094,14 @@ class CuraEngineBackend(QObject, Backend): self._change_timer.timeout.disconnect(self.slice) def _onPreferencesChanged(self, preference: str) -> None: - if preference != "general/auto_slice": + if preference != "general/auto_slice" and preference != "info/send_engine_crash": return - auto_slice = self.determineAutoSlicing() - if auto_slice: - self._change_timer.start() + if preference == "general/auto_slice": + auto_slice = self.determineAutoSlicing() + if auto_slice: + self._change_timer.start() + elif preference == "info/send_engine_crash": + os.environ["use_sentry"] = "1" if CuraApplication.getInstance().getPreferences().getValue("info/send_engine_crash") else "0" def tickle(self) -> None: """Tickle the backend so in case of auto slicing, it starts the timer.""" diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index a12e9e655d..fe7137150b 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -1,5 +1,7 @@ # Copyright (c) 2023 UltiMaker # Cura is released under the terms of the LGPLv3 or higher. +import uuid + import os import numpy @@ -30,6 +32,7 @@ from cura.CuraApplication import CuraApplication from cura.Scene.CuraSceneNode import CuraSceneNode from cura.OneAtATimeIterator import OneAtATimeIterator from cura.Settings.ExtruderManager import ExtruderManager +from cura.CuraVersion import CuraVersion NON_PRINTING_MESH_SETTINGS = ["anti_overhang_mesh", "infill_mesh", "cutting_mesh"] @@ -332,6 +335,11 @@ class StartSliceJob(Job): self._buildGlobalSettingsMessage(stack) self._buildGlobalInheritsStackMessage(stack) + user_id = uuid.getnode() # On all of Cura's supported platforms, this returns the MAC address which is pseudonymical information (!= anonymous). + user_id %= 2 ** 16 # So to make it anonymous, apply a bitmask selecting only the last 16 bits. This prevents it from being traceable to a specific user but still gives somewhat of an idea of whether it's just the same user hitting the same crash over and over again, or if it's widespread. + self._slice_message.sentry_id = "{user_id}" + self._slice_message.cura_version = CuraVersion + # Build messages for extruder stacks for extruder_stack in global_stack.extruderList: self._buildExtruderMessage(extruder_stack) diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 473948bc46..a659a6de97 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -78,6 +78,8 @@ class SimulationView(CuraView): self._minimum_path_num = 0 self.currentLayerNumChanged.connect(self._onCurrentLayerNumChanged) + self._current_feedrates = {} + self._lengths_of_polyline ={} self._busy = False self._simulation_running = False @@ -400,6 +402,15 @@ class SimulationView(CuraView): def getMaxFeedrate(self) -> float: return self._max_feedrate + def getSimulationTime(self, currentIndex) -> float: + try: + return (self._lengths_of_polyline[self._current_layer_num][currentIndex] / self._current_feedrates[self._current_layer_num][currentIndex])[0] + + except: + # In case of change in layers, currentIndex comes one more than the items in the lengths_of_polyline + # We give 1 second time for layer change + return 1.0 + def getMinThickness(self) -> float: if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. return 0.0 # If it's still max-float, there are no measurements. Use 0 then. @@ -524,8 +535,10 @@ class SimulationView(CuraView): visible_indicies_with_extrusion = numpy.where(numpy.isin(polyline.types, visible_line_types_with_extrusion))[0] if visible_indices.size == 0: # No items to take maximum or minimum of. continue + self._lengths_of_polyline[layer_index] = polyline.lineLengths visible_feedrates = numpy.take(polyline.lineFeedrates, visible_indices) visible_feedrates_with_extrusion = numpy.take(polyline.lineFeedrates, visible_indicies_with_extrusion) + self._current_feedrates[layer_index] = polyline.lineFeedrates visible_linewidths = numpy.take(polyline.lineWidths, visible_indices) visible_linewidths_with_extrusion = numpy.take(polyline.lineWidths, visible_indicies_with_extrusion) visible_thicknesses = numpy.take(polyline.lineThicknesses, visible_indices) diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml index a82d1e3db9..216095c15c 100644 --- a/plugins/SimulationView/SimulationViewMainComponent.qml +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -136,7 +136,7 @@ Item Timer { id: simulationTimer - interval: 100 + interval: UM.SimulationView.simulationTime running: false repeat: true onTriggered: diff --git a/plugins/SimulationView/SimulationViewProxy.py b/plugins/SimulationView/SimulationViewProxy.py index 669f7fdbcc..576281874c 100644 --- a/plugins/SimulationView/SimulationViewProxy.py +++ b/plugins/SimulationView/SimulationViewProxy.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from typing import TYPE_CHECKING +import numpy from PyQt6.QtCore import QObject, pyqtSignal, pyqtProperty from UM.FlameProfiler import pyqtSlot from UM.Application import Application @@ -11,6 +12,11 @@ if TYPE_CHECKING: class SimulationViewProxy(QObject): + + S_TO_MS = 1000 + SPEED_OF_SIMULATION = 10 + FACTOR = S_TO_MS/SPEED_OF_SIMULATION + def __init__(self, simulation_view: "SimulationView", parent=None) -> None: super().__init__(parent) self._simulation_view = simulation_view @@ -54,6 +60,14 @@ class SimulationViewProxy(QObject): def currentPath(self): return self._simulation_view.getCurrentPath() + @pyqtProperty(int, notify=currentPathChanged) + def simulationTime(self): + # Extracts the currents paths simulation time (in seconds) for the current path from the dict of simulation time of the current layer. + # We multiply the time with 100 to make it to ms from s.(Should be 1000 in real time). This scaling makes the simulation time 10x faster than the real time. + simulationTimeOfpath = self._simulation_view.getSimulationTime(self._simulation_view.getCurrentPath()) * SimulationViewProxy.FACTOR + # Since the timer cannot process time less than 1 ms, we put a lower limit here + return int(max(1, simulationTimeOfpath)) + @pyqtProperty(int, notify=currentPathChanged) def minimumPath(self): return self._simulation_view.getMinimumPath() diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py index aed38a3949..9a11bb886c 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py @@ -331,7 +331,7 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): return False [printer, *_] = self._printers - return printer.pinterType in ("ultimaker_methodx", "ultimaker_methodxl") + return printer.name in ("ultimaker_methodx", "ultimaker_methodxl") @pyqtProperty(bool, notify=_cloudClusterPrintersChanged) def supportsPrintJobActions(self) -> bool: diff --git a/requirements.txt b/requirements.txt index dfa974ef7d..76339c884f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,41 +1,47 @@ ### Direct requirements for Uranium and libCharon ### -PyQt6-sip==13.4.1 \ - --hash=sha256:0df998f2b6ceeacfd10de773441572e215be0c9cae566cc7dd36e231bf714a12 \ - --hash=sha256:224575e84805c4317bacd5d1b8e93e0ad5c48685dadbbe1e902d4ebe16f22828 \ - --hash=sha256:36ae29cdc223cacc1257d0f5075cf81474550c6d26b728f922487a2aa935f130 \ - --hash=sha256:3a674c591d4274d4ea8127205290e927a7dab0eb87a0038d4f4ea1d430782649 \ - --hash=sha256:3ef9392e4ae29d393b79237d85840cdc6b8831f36eed5d56c7d9b329b380cc8d \ - --hash=sha256:43935873d60f57719632840d517afee04ef8f30e92cfe0dadc7e6326691920fc \ - --hash=sha256:5731f22618435654352ef07684549a17be82b75254227fc80b4b5b0b59fc6656 \ - --hash=sha256:5bc4beb6fb1de4c9ba8beee7b1a4a813fa888c3b095206dafcd25d7e6e4ed2a7 \ - --hash=sha256:5c36ab984402e96792eebf4b031abfaa589aa20af3190a79c54502c16964d97e \ - --hash=sha256:a2a0461992c6657f343308b150c4d6b57e9e7a0e5c2f79538434e7fb869ea827 \ - --hash=sha256:a81490ee84d7a41a126b116081bd97d758f41bf706aee0a8cec24d6e4c660184 \ - --hash=sha256:e00e287ea05bbc293fc6e2198301962af9b7b622bd2daf4288f925a88ae35dc9 \ - --hash=sha256:e670a7b2fb7e32204ce67d274017bfff3e21139d217d60cebbfcb75b019c91ee \ - --hash=sha256:ee06f255787a0b4957f357f93b78d2a11ca3761916833e3afa83f1381d4d1a46 \ - --hash=sha256:fbee0d554e0e98f56dbf6d94b00a28cc32425938ad7ae98fd91f8822c5b24d45 \ - --hash=sha256:fcc6d78314783f4a193f02353f431b7ea4d357f47c3c7a7d0740e723f69c64dc -PyQt6==6.4.2 \ - --hash=sha256:18d1daf98d9236d55102cdadafd1056f5802f3c9288fcf7238569937b71a89f0 \ - --hash=sha256:25bd399b4a95dce65d5f937c1aa85d3c7e14a21745ae2a4ca14c0116cd104290 \ - --hash=sha256:740244f608fe15ee1d89695c43f31a14caeca41c4f02ac36c86dfba4a5d5813d \ - --hash=sha256:c128bc0f17833e324593e3db83e99470d451a197dd17ff0333927b946c935bd9 -PyQt6-Qt6==6.4.2 \ - --hash=sha256:9f07c3c100cb46cca4074965e7494d4df4f0fc016497d5303c1fe135822876e1 \ - --hash=sha256:a29b8c858babd523e80c8db5f8fd19792641588ec04eab49af18b7a4423eb99f \ - --hash=sha256:c0e91d0275d428496cacff717a9b719c52bfa52b21f124d638b79cc2217bc81e \ - --hash=sha256:d19c4e72615762cd6f0b043f23fa5f0b02656091427ce6de1efccd58e10e6a53 -PyQt6-NetworkAuth==6.4.0 \ - --hash=sha256:ab6178b3b2902ae9939a148555cfcee8c7803d6b0d5924cd1bd8f3407b8b9210 \ - --hash=sha256:c16ec80232d88024b60d04386a23cc93067e5644a65f47f26ffb13d84dcd4a6d \ - --hash=sha256:c302cd0d838c7229eda5e26e0b1b3d3ec4f8720f8d9379472bce5a89ff0735c2 \ - --hash=sha256:d948fc0cf43b64afbda2acb5bf2392f785a1e7a2950d79ea850c1a3f4ae12f1a -PyQt6-NetworkAuth-Qt6==6.4.2 \ - --hash=sha256:179094bcb4d4d056316c22d3d067cd94d4591da23f804461bfb025ccfa29b2b4 \ - --hash=sha256:1de6abbb5fa6585b97ae49d3f64b0dfad40bd56b1a31744d9775ff26247241c8 \ - --hash=sha256:79ec4b0fc9450bbedbff03541b93b10d1c7e761cd2cc16ce70d2b09dcdf8c720 \ - --hash=sha256:d96d557fe61edb9b68d189f270f0393d6579c8d308e6b0d41bc0699371d7cb4e +PyQt6-sip==13.6.0 \ + --hash=sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0 \ + --hash=sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357 \ + --hash=sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b \ + --hash=sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778 \ + --hash=sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562 \ + --hash=sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8 \ + --hash=sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3 \ + --hash=sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4 \ + --hash=sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5 \ + --hash=sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea \ + --hash=sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df \ + --hash=sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab \ + --hash=sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f \ + --hash=sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012 \ + --hash=sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436 \ + --hash=sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228 \ + --hash=sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916 \ + --hash=sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5 \ + --hash=sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d \ + --hash=sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4 \ + --hash=sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9 +PyQt6==6.6.0 \ + --hash=sha256:33655db05ac2de699320f035250c21434c77144a6a2943aca3f4c579dabc3f7b \ + --hash=sha256:3ef68830a9b32050c30f7962c56a5927802c9193b68eaf405faecb8ce9ae10a8 \ + --hash=sha256:d41512d66044c2df9c5f515a56a922170d68a37b3406ffddc8b4adc57181b576 \ + --hash=sha256:fc7185d65755f26d7a6842492ec5398c92544dc4eafbbcbef1b1922aca585c96 +PyQt6-Qt6==6.6.0 \ + --hash=sha256:1b079a33088d32ff47872cdb37fd15aa42101f0be46c3340244483849b781438 \ + --hash=sha256:8cb30d64a4d32465ea1686bc827cbe452225fb387c4873356b0fa7b9ae63534f \ + --hash=sha256:a151f34712cd645111e89cb30b02e5fb69c9dcc3603ab3c03a561e874bd7cbcf \ + --hash=sha256:e5483ae04bf107411c7469f1be9f9e2eb9840303e788b3ac524fe30af90d45f4 +PyQt6-NetworkAuth==6.6.0 \ + --hash=sha256:7b90b81792fe53105287c8cbb5e4b22bc44a482268ffb7d3e33f852807f86182 \ + --hash=sha256:c7e2335159aa795e2fe6fb069ccce6308672ab80f26c50fab57caf957371cbb5 \ + --hash=sha256:cdfc0bfaea16a9e09f075bdafefb996aa9fdec392052ba4fb3cbac233c1958fb \ + --hash=sha256:f60ff9a62f5129dc2a9d4c495fb47f9a03e4dfb666b50fb7d61f46e89bf7b6a2 +PyQt6-NetworkAuth-Qt6==6.6.0 \ + --hash=sha256:481d9093e1fb1ac6843d8beabcd359cc34b74b9a2cbb3e2b68d96bd3f178d4e0 \ + --hash=sha256:4cc48fd375730a0ba5fbed9d64abb2914f587377560a78a63aff893f9e276a45 \ + --hash=sha256:5006deabf55304d4a3e0b3c954f93e5835546b11e789d14653a2493d12d3a063 \ + --hash=sha256:bcd56bfc892fec961c51eba3c0bf32ba8317a762d9e254d3830569611ed569d6 + certifi==2023.5.7; \ --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 cryptography==41.0.1 \ diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b640fb5746..62143cf8f8 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -8305,6 +8305,88 @@ } } }, + "ppr": + { + "label": "Print Process Reporting", + "type": "category", + "icon": "DocumentFilled", + "description": "Reporting events that go out of set thresholds", + "enabled": false, + "children": + { + "ppr_enable": + { + "label": "Enable Print Process Reporting", + "description": "Enable print process reporting for setting threshold values for possible fault detection.", + "type": "bool", + "enabled": false, + "default_value": false, + "value": false, + "settable_per_mesh": false, + "settable_per_extruder": false + }, + "flow_warn_limit": + { + "label": "Flow Warning", + "description": "Limit on the flow warning for detection.", + "default_value": "15.0", + "enabled": "ppr_enable", + "unit": "%", + "type": "float", + "settable_per_extruder": true + }, + "flow_anomaly_limit": + { + "label": "Flow Limit", + "description": "Limit on flow anomaly for detection.", + "default_value": "25.0", + "enabled": "ppr_enable", + "unit": "%", + "type": "float", + "settable_per_extruder": true + }, + "print_temp_warn_limit": + { + "label": "Print temperature Warning", + "description": "Limit on Print temperature warning for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "3.0", + "enabled": "ppr_enable", + "settable_per_extruder": true + }, + "print_temp_anomaly_limit": + { + "label": "Print temperature Limit", + "description": "Limit on Print Temperature anomaly for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "7.0", + "enabled": "ppr_enable", + "settable_per_extruder": true + }, + "bv_temp_warn_limit": + { + "label": "Build Volume temperature Warning", + "description": "Limit on Build Volume Temperature warning for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "7.5", + "enabled": "ppr_enable", + "settable_per_extruder": false + }, + "bv_temp_anomaly_limit": + { + "label": "Build Volume temperature Limit", + "description": "Limit on Build Volume temperature Anomaly for detection.", + "unit": "\u00b0C", + "type": "float", + "default_value": "10.0", + "enabled": "ppr_enable", + "settable_per_extruder": false + } + } + }, "command_line_settings": { "label": "Command Line Settings", diff --git a/resources/definitions/ultimaker_method_base.def.json b/resources/definitions/ultimaker_method_base.def.json index 8e9034c954..d45f54f8b9 100644 --- a/resources/definitions/ultimaker_method_base.def.json +++ b/resources/definitions/ultimaker_method_base.def.json @@ -329,6 +329,7 @@ "machine_name": { "default_value": "UltiMaker Method" }, "machine_nozzle_cool_down_speed": { "value": 0.8 }, "machine_nozzle_heat_up_speed": { "value": 3.5 }, + "machine_scale_fan_speed_zero_to_one": { "value": true }, "machine_start_gcode": { "default_value": "" }, "material_bed_temperature": { "enabled": "machine_heated_bed" }, "material_bed_temperature_layer_0": { "enabled": "machine_heated_bed" }, diff --git a/resources/qml/Dialogs/AboutDialog.qml b/resources/qml/Dialogs/AboutDialog.qml index 8ea0c01888..947b46269a 100644 --- a/resources/qml/Dialogs/AboutDialog.qml +++ b/resources/qml/Dialogs/AboutDialog.qml @@ -45,6 +45,16 @@ UM.Dialog anchors.centerIn: parent } + Image + { + id: enterpriseLogo + visible: CuraApplication.isEnterprise + source: UM.Theme.getImage("enterprise") + fillMode: Image.PreserveAspectFit + + anchors.bottom: parent.bottom + } + UM.Label { id: version diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index 32bbcd5053..587084444c 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -120,6 +120,10 @@ UM.PreferencesPage UM.Preferences.resetPreference("info/send_slice_info") sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info")) + + UM.Preferences.resetPreference("info/send_engine_crash") + sendEngineCrashCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_engine_crash")) + UM.Preferences.resetPreference("info/automatic_update_check") checkUpdatesCheckbox.checked = boolCheck(UM.Preferences.getValue("info/automatic_update_check")) @@ -855,6 +859,21 @@ UM.PreferencesPage font: UM.Theme.getFont("medium_bold") text: catalog.i18nc("@label", "Privacy") } + UM.TooltipArea + { + width: childrenRect.width + height: visible ? childrenRect.height : 0 + text: catalog.i18nc("@info:tooltip", "Should slicing crashes be automatically reported to Ultimaker? Note, no models, IP addresses or other personally identifiable information is sent or stored.") + + UM.CheckBox + { + id: sendEngineCrashCheckbox + text: catalog.i18nc("@option:check","Send (anonymous) engine crash reports") + checked: boolCheck(UM.Preferences.getValue("info/send_engine_crash")) + onCheckedChanged: UM.Preferences.setValue("info/send_engine_crash", checked) + } + } + UM.TooltipArea { width: childrenRect.width diff --git a/resources/themes/cura-light/images/enterprise.png b/resources/themes/cura-light/images/enterprise.png new file mode 100644 index 0000000000..6d92d80adb Binary files /dev/null and b/resources/themes/cura-light/images/enterprise.png differ