From 3f1370489b2a03c3ab6c11129c17036a4d2feec7 Mon Sep 17 00:00:00 2001 From: Negar Date: Fri, 20 Sep 2024 00:46:17 +1000 Subject: [PATCH] chore: native binaries installation docs and cd refinements (#442) * docs: updating installation docs * docs: update docs * docs: update docs * docs: update docs - PR reviewa * docs: update docs on supported architectures * docs: tweak wording * refactor: removing choco; updating snapshots and doctor; tweaking CD * chore: patch pre-commit ignores for vendor folder * chore: patching portability test --------- Co-authored-by: Neil Campbell Co-authored-by: Altynbek Orumbayev --- .../workflows/publish-release-packages.yaml | 97 +----------------- .pre-commit-config.yaml | 2 + README.md | 86 +++++++++------- scripts/chocolatey/algokit/README.md | 39 ------- scripts/chocolatey/algokit/algokit.nuspec | 33 ------ .../chocolatey/algokit/algorand-logo-512.png | Bin 16985 -> 0 bytes scripts/chocolatey/algokit/tools/LICENSE.txt | 22 ---- .../chocolatey/algokit/tools/VERIFICATION.txt | 11 -- .../algokit/tools/chocolateyinstall.ps1 | 53 ---------- .../algokit/tools/chocolateyuninstall.ps1 | 24 ----- scripts/update-chocolatey-package.ps1 | 38 ------- src/algokit/cli/doctor.py | 4 +- .../auth0/authentication/token_verifier.py | 1 - src/algokit/core/utils.py | 2 +- tests/doctor/test_doctor.py | 7 +- ...ll_commands_bad_exit[windows].approved.txt | 7 +- ...l_commands_not_found[windows].approved.txt | 8 +- ...st_doctor_successful[windows].approved.txt | 6 +- ..._with_weird_values_on_windows.approved.txt | 8 +- tests/portability/test_pyinstaller_binary.py | 2 +- 20 files changed, 74 insertions(+), 376 deletions(-) delete mode 100644 scripts/chocolatey/algokit/README.md delete mode 100644 scripts/chocolatey/algokit/algokit.nuspec delete mode 100644 scripts/chocolatey/algokit/algorand-logo-512.png delete mode 100644 scripts/chocolatey/algokit/tools/LICENSE.txt delete mode 100644 scripts/chocolatey/algokit/tools/VERIFICATION.txt delete mode 100644 scripts/chocolatey/algokit/tools/chocolateyinstall.ps1 delete mode 100644 scripts/chocolatey/algokit/tools/chocolateyuninstall.ps1 delete mode 100644 scripts/update-chocolatey-package.ps1 diff --git a/.github/workflows/publish-release-packages.yaml b/.github/workflows/publish-release-packages.yaml index 5c4d0cf04..fe9216c7e 100644 --- a/.github/workflows/publish-release-packages.yaml +++ b/.github/workflows/publish-release-packages.yaml @@ -3,7 +3,7 @@ name: Publish packages to public repositories on: workflow_call: inputs: - wheelArtifactName: + artifactName: required: true type: string description: "The github artifact holding the wheel file which will be published" @@ -16,11 +16,6 @@ on: default: true type: boolean description: "Publish to brew repository" - do_chocolatey: - required: false - default: true - type: boolean - description: "Publish to Chocolatey repository" do_snap: required: false default: true @@ -31,32 +26,6 @@ on: default: true type: boolean description: "Publish to Winget repository" - workflow_dispatch: - inputs: - release_version: - required: true - type: string - description: "The release version that will be published (e.g. 0.1.0). Note this is not the tag version." - do_brew: - required: false - default: true - type: boolean - description: "Publish to brew repository" - do_chocolatey: - required: false - default: true - type: boolean - description: "Publish to Chocolatey repository" - do_winget: - required: false - default: true - type: boolean - description: "Publish to Winget repository" - do_snap: - required: false - default: true - type: boolean - description: "Publish to snap repository" jobs: publish-brew: @@ -66,84 +35,24 @@ jobs: - name: Checkout source code uses: actions/checkout@v4 - # Download either via release or provided artifact - name: Download wheel from release - if: ${{ github.event_name == 'workflow_dispatch' }} run: gh release download v${{ inputs.release_version }} --pattern "*.whl" --dir dist env: GH_TOKEN: ${{ github.token }} - - name: Download wheel from artifact - if: ${{ github.event_name == 'workflow_call' }} - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.wheelArtifactName }} - path: dist - - - name: Download macOS binary from release - if: ${{ github.event_name == 'workflow_dispatch' }} - run: gh release download ${{ inputs.release }} --pattern "*-brew.tar.gz" --dir dist + - name: Download binary artifact from release + run: gh release download v${{ inputs.release_version }} --pattern "*-brew.tar.gz" --dir dist env: GH_TOKEN: ${{ github.token }} - - name: Download macOS binary from artifact - uses: actions/download-artifact@v4 - if: ${{ github.event_name == 'workflow_call' }} - with: - name: ${{ inputs.binaryArtifactName }} - path: dist - - name: Set Git user as GitHub actions run: git config --global user.email "actions@github.com" && git config --global user.name "github-actions" - - name: ls dist folder - run: ls -la dist - - name: Update homebrew cask run: scripts/update-brew-cask.sh "dist/algokit*-py3-none-any.whl" "dist/algokit*-macos_arm64-brew.tar.gz" "dist/algokit*-macos_x64-brew.tar.gz" "algorandfoundation/homebrew-tap" env: TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} - publish-chocolatey: - runs-on: windows-latest - if: ${{ inputs.do_chocolatey }} - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - # Download either via release or provided artifact - - name: Download release - if: ${{ github.event_name == 'workflow_dispatch' }} - run: gh release download v${{ inputs.release_version }} --pattern "*.whl" --dir dist - env: - GH_TOKEN: ${{ github.token }} - - - name: Download artifact - if: ${{ github.event_name == 'workflow_call' }} - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.artifactName }} - path: dist - - - name: Update chocolatey files - id: update_chocolatey_files - run: scripts/update-chocolatey-package.ps1 - - - name: Build package - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: pack --version ${{ steps.update_chocolatey_files.outputs.version }} .\scripts\chocolatey\algokit\algokit.nuspec - - - name: Set API key - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: apikey --api-key ${{ secrets.CHOCOLATEY_API_KEY }} -source https://push.chocolatey.org/ - - - name: Push package - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: push --source https://push.chocolatey.org/ - publish-winget: runs-on: windows-latest if: ${{ inputs.do_winget }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3fadb5761..21e835a71 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,6 +22,7 @@ repos: additional_dependencies: [] minimum_pre_commit_version: "0" files: "^(src|tests)/" + exclude: "^src/algokit/core/_vendor/" - id: mypy name: mypy description: "`mypy` will check Python types for correctness" @@ -32,3 +33,4 @@ repos: additional_dependencies: [] minimum_pre_commit_version: "2.9.2" files: "^(src|tests)/" + exclude: "^src/algokit/core/_vendor/" diff --git a/README.md b/README.md index 5a41641a5..8879525d0 100644 --- a/README.md +++ b/README.md @@ -86,18 +86,23 @@ This is an open source project managed by the Algorand Foundation. See the [cont The key required dependency is Python 3.10+, but some of the installation options below will install that for you. We recommend using Python 3.12+, as the `algokit compile python` command requires this version. -AlgoKit also has some runtime dependencies that also need to be available for particular commands. - > **Note** -> You can still install and use AlgoKit without these dependencies and AlgoKit will tell you if you are missing one for a given command. +> You can still install and use AlgoKit without these dependencies, and AlgoKit will tell you if you are missing one for a given command. - **Git**: Essential for creating and updating projects from templates. Installation guide available at [Git Installation](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). - **Docker**: Necessary for running the AlgoKit LocalNet environment. Docker Compose version 2.5.0 or higher is required. See [Docker Installation](https://docs.docker.com/get-docker/). - **Node.js**: For those working on frontend templates or building contracts using TEALScript. **Minimum required versions are Node.js `v18` and npm `v9`**. Instructions can be found at [Node.js Installation](https://nodejs.org/en/download/). +> **Note** +> If you have previously installed AlgoKit using `pipx` and would like to switch to a different installation method, please ensure that +> you first uninstall the existing version by running `pipx uninstall algokit`. Once uninstalled, you can follow the installation instructions for your preferred platform. + ## Cross-platform installation -AlgoKit can be installed using OS specific package managers, or using the python tool [pipx](https://pypa.github.io/pipx/) see below for specific installation instructions. +AlgoKit can be installed using OS specific package managers, or using the python tool [pipx](https://pypa.github.io/pipx/). +See below for specific installation instructions. + +### Installation Methods - [Windows](#install-algokit-on-windows) - [Mac](#install-algokit-on-mac) @@ -107,36 +112,22 @@ AlgoKit can be installed using OS specific package managers, or using the python ## Install AlgoKit on Windows > **Note** -> This method will install the most recent python3 version [via winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/). If you already have python 3.10+ installed, you may [prefer to use pipx directly instead](#install-algokit-with-pipx-on-any-os) so you can control the python version used. +> AlgoKit is supported on Windows 10 1709 (build 16299) and later. +> We only publish an x64 binary, however it also runs on ARM devices by default using the built in x64 emulation feature. 1. Ensure prerequisites are installed + - [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/) (should be installed by default on recent Windows 10 or later) - [Git](https://github.com/git-guides/install-git#install-git-on-windows) (or `winget install git.git`) - [Docker](https://docs.docker.com/desktop/install/windows-install/) (or `winget install docker.dockerdesktop`) > **Note** > See [our LocalNet documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/localnet.md#prerequisites) for more tips on installing Docker on Windows -2. Install using WinGet - - 1. Install python: `winget install python.python.3.11` - 2. Restart the terminal to ensure Python and pip are available on the path - - > **Note** - > Windows has a feature called **App Execution Aliases** that provides redirects for the Python command that guide users to the - > Windows Store. Unfortunately these aliases can prevent normal execution of Python if Python is installed via other means, to disable them - > search for **Manage app execution aliases** from the start menu, and then turn off entries listed as - > **App Installer python.exe** or **App Installer python3.exe**. - - 3. Install pipx: +2. Install using winget - ``` - pip install --user pipx - python -m pipx ensurepath - ``` - - 4. Restart the terminal to ensure pipx is available on the path - 5. Install AlgoKit via pipx: `pipx install algokit` - 6. Restart the terminal to ensure AlgoKit is available on the path + ```shell + winget install algokit + ``` 3. [Verify installation](#verify-installation) @@ -144,13 +135,13 @@ AlgoKit can be installed using OS specific package managers, or using the python Some useful commands for updating or removing AlgoKit in the future. -- To update AlgoKit: `pipx upgrade algokit` -- To remove AlgoKit: `pipx uninstall algokit` +- To update AlgoKit: `winget upgrade algokit` +- To remove AlgoKit: `winget uninstall algokit` ## Install AlgoKit on Mac > **Note** -> This method will install Python 3.10 as a dependency via Homebrew. If you already have python installed, you may prefer to use `pipx install algokit` as explained [here](#install-algokit-with-pipx-on-any-os). +> AlgoKit is supported on macOS Big Sur (11) and later for both x64 and ARM (Apple Silicon) 1. Ensure prerequisites are installed @@ -160,7 +151,12 @@ Some useful commands for updating or removing AlgoKit in the future. > **Note** > Docker requires MacOS 11+ -2. Install using Homebrew `brew install algorandfoundation/tap/algokit` +2. Install using Homebrew + + ```shell + brew install algorandfoundation/tap/algokit + ``` + 3. Restart the terminal to ensure AlgoKit is available on the path 4. [Verify installation](#verify-installation) @@ -173,18 +169,29 @@ Some useful commands for updating or removing AlgoKit in the future. ## Install AlgoKit on Linux -1. Ensure prerequisites are installed - - - [Python 3.10+](https://www.python.org/downloads/) +> **Note** +> AlgoKit is compatible with Ubuntu 16.04 and later, Debian, RedHat, and any distribution that supports [Snap](https://snapcraft.io/docs/installing-snapd), but it is only supported on x64 architecture; ARM is not supported. - > **Note** - > There is probably a better way to install Python than to download it directly, e.g. your local Linux package manager +1. Ensure prerequisites are installed - - [pipx](https://pypa.github.io/pipx/#on-linux-install-via-pip-requires-pip-190-or-later) + - [Snap](https://snapcraft.io/docs/installing-snapd) (should be installed by default on Ubuntu 16.04.4 LTS (Xenial Xerus) or later) - [Git](https://github.com/git-guides/install-git#install-git-on-linux) - [Docker](https://docs.docker.com/desktop/install/linux-install/) -2. Continue with step 2 in the following section to install via [pipx](#install-algokit-with-pipx-on-any-os) +2. Install using snap + + ```shell + snap install algokit --classic + ``` + +3. [Verify installation](#verify-installation) + +### Maintenance + +Some useful commands for updating or removing AlgoKit in the future. + +- To update AlgoKit: `snap refresh algokit` +- To remove AlgoKit: `snap remove --purge algokit` ## Install AlgoKit with pipx on any OS @@ -195,7 +202,12 @@ Some useful commands for updating or removing AlgoKit in the future. - [Git](https://github.com/git-guides/install-git) - [Docker](https://docs.docker.com/get-docker/) -2. Install using pipx `pipx install algokit` +2. Install using pipx + + ```shell + pipx install algokit + ``` + 3. Restart the terminal to ensure AlgoKit is available on the path 4. [Verify installation](#verify-installation) diff --git a/scripts/chocolatey/algokit/README.md b/scripts/chocolatey/algokit/README.md deleted file mode 100644 index ae6c5d932..000000000 --- a/scripts/chocolatey/algokit/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Chocolatey Package - -This directory contains the nuspec file to define the [Chocolatey](https://chocolatey.org/) repository package for Windows and various associate powershell scripts. - -# Installing - -> __Note__ -> This will install the most recent python3 version through chocolatey. If you already have python installed, you may prefer to use `pipx install algokit` as explained in [Installing](../../../README.md). - -1. Ensure chocolatey is installed - https://chocolatey.org/install -2. Run `choco install algokit` from an administrator powershell/cmd/terminal window -3. Test algokit is installed `algokit --version` - -# Development - -## Building and publishing locally - -1. Ensure wheel file is built `poetry build` (make sure there's only a single file in _dist_ directory) -2. Set version field in _algokit.nuspec_ - > __Note__ - > Versions with a pre-release suffix such as 1.2.3-beta are automatically designated as pre-release packages by chocolatey -3. `cd .\scripts\chocolatey\algokit` -4. `choco pack` -5. `choco apikey --api-key [API_KEY_HERE] -source https://push.chocolatey.org/` -6. `choco push --source https://push.chocolatey.org/` - -Also see [Chocolatey docs](https://docs.chocolatey.org/en-us/create/create-packages). - -## Installing from local packages - -- `cd .\scripts\chocolatey\algokit` -- Install - `choco install algokit -pre --source "'.;https://community.chocolatey.org/api/v2/'" -y` -- Uninstall - `choco uninstall algokit -y` -- Upgrade - `choco upgrade algokit -pre --source "'.;https://community.chocolatey.org/api/v2/'" -y` - -# Issues - -- Chocolatey doesn't support full sematic release v2 versions yet. This means version identifiers with dot notation are not supported (1.2.3-beta.12). See [this issue](https://github.com/chocolatey/choco/issues/1610). -- Installing using the `-pre` tag on will also install pre-release verisons of dependencies. At the time of development, this installed python 3.12.0-a2 which has errors installing algokit. Solution is to `choco install python3` prior to `choco install algokit -pre`. See [nuspec](https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#pre-release-versions) for clarification. diff --git a/scripts/chocolatey/algokit/algokit.nuspec b/scripts/chocolatey/algokit/algokit.nuspec deleted file mode 100644 index 032dd097c..000000000 --- a/scripts/chocolatey/algokit/algokit.nuspec +++ /dev/null @@ -1,33 +0,0 @@ - - - - - algokit - 0.1.0-beta - https://github.com/algorandfoundation/algokit-cli/blob/main/scripts/chocolatey - algorand-foundation - AlgoKit - Algorand Foundation - https://www.algorand.foundation/developers - https://rawcdn.githack.com/algorandfoundation/algokit-cli/733cbc7714db7d4786cb9c0de60c991c63dcc3b7/scripts/chocolatey/algokit/algorand-logo-512.png?min=1 - https://github.com/algorandfoundation/algokit-cli/blob/main/LICENSE - false - https://github.com/algorandfoundation/algokit-cli - https://github.com/algorandfoundation/algokit-cli/blob/main/README.md - https://github.com/algorandfoundation/algokit-cli/issues - https://github.com/algorandfoundation/algokit-cli/blob/main/CHANGELOG.md - algokit algorand developers python typescript hello-world smart-contract beaker - The Algorand AlgoKit CLI is the one-stop shop tool for developers building on the Algorand network. - - - - - - - - - - - diff --git a/scripts/chocolatey/algokit/algorand-logo-512.png b/scripts/chocolatey/algokit/algorand-logo-512.png deleted file mode 100644 index e6a3f99239d2864574ffe62c529d97b97541076b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16985 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 - if ($LASTEXITCODE -ne 0) { - Throw "Error searching for existing packages" - } -} - -# uninstall existing package if present -if ($pipxListOutput -match "$env:ChocolateyPackageName.*") { - &{ - #pipx outputs to stderr as part of normal execution, so ignore stderr - $ErrorActionPreference = 'Continue' - python -m pipx uninstall $env:ChocolateyPackageName 2>&1 - if ($LASTEXITCODE -ne 0) { - Throw "Error removing existing version" - } - } -} - -# install the bundled wheel file. -&{ - #pipx outputs to stderr as part of normal execution, so ignore stderr - $ErrorActionPreference = 'Continue' - python -m pipx install $wheelFileName[0].FullName 2>&1 - if ($LASTEXITCODE -ne 0) { - Throw "Error installing $($wheelFileName[0].FullName)" - } -} - -#setup shim -$pipx_list = python -m pipx list --json | ConvertFrom-Json -$algokit_path = $pipx_list.venvs.algokit.metadata.main_package.app_paths.__Path__ -Install-BinFile -Name algokit -Path $algokit_path \ No newline at end of file diff --git a/scripts/chocolatey/algokit/tools/chocolateyuninstall.ps1 b/scripts/chocolatey/algokit/tools/chocolateyuninstall.ps1 deleted file mode 100644 index 6bd79a2c3..000000000 --- a/scripts/chocolatey/algokit/tools/chocolateyuninstall.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -$ErrorActionPreference = 'Stop' - -# ensure pipx is installed. Just in case someone has removed it manually -python -m pip install --disable-pip-version-check --no-warn-script-location --user pipx -if ($LASTEXITCODE -ne 0) { - Throw "Error configuring pipx for uninstalling" -} - -# zap it -&{ - #pipx outputs to stderr as part of normal execution, so ignore stderr - $ErrorActionPreference = 'Continue' - python -m pipx uninstall $env:ChocolateyPackageName 2>&1 - if ($LASTEXITCODE -ne 0) { - if ($cmdOutput -match "Nothing to uninstall" ) { - Write-Output "$($env:ChocolateyPackageName) already uninstalled by pipx. Ignoring" - } - else { - Throw "Error running pipx uninstall $($env:ChocolateyPackageName)" - } - } -} - -Uninstall-BinFile -Name algokit \ No newline at end of file diff --git a/scripts/update-chocolatey-package.ps1 b/scripts/update-chocolatey-package.ps1 deleted file mode 100644 index fec712094..000000000 --- a/scripts/update-chocolatey-package.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -# Re-create the version based on the wheel file name. -# NOTE: x.y.x-beta.12 versions are not supported by chocolatey and need to be rewritten as x.y.z-beta12 (however this will likely change soon) -# "special version part" requirements. <20 characters, no '.' no '+' -$wheelFiles = Get-ChildItem -File -Filter algokit*-py3-none-any.whl dist -if ($wheelFiles.count -ne 1) { - Throw "Packaging error. build artifact contained $($wheelFileName.count) normally named wheel files" -} -$wheelFile = $wheelFiles[0] -$wheelFileName = $wheelFile.Name -if ($wheelFileName -Match '-([0-9]+\.[0-9]+\.[0-9]+)b?([0-9]*)(\+(.*?))?(.[0-9]+)?-') { - $version_number = $Matches[1] - $version_beta = $Matches[2] - $version_branch = $Matches[4] - $version_branch = $version_branch ? $version_branch.Replace(".", "") : "" # dots aren't valid here - $version_betanumber = $Matches[5] - $version_beta_truncated = "beta$($version_beta)$($version_branch)" - #$version_beta_truncated = "beta$($version_beta)$($version_branch)$($version_betanumber)" # When chocolatey supports semver v2.0 - $version_beta_truncated = $version_beta_truncated.subString(0, [System.Math]::Min(20, $version_beta_truncated.Length - 1)) # chocolatey has a limit of 20 characters on "special version part" -} -else { - Throw "Packaging error. Unrecognised file name pattern $($wheelFileName[0].Name)" -} - -$version = $version_number -$release_tag = "v${version_number}" -if ($version_beta) { - $version = "$($version)-$($version_beta_truncated)" - $release_tag = "${release_tag}-beta.${version_beta}" -} - -# Update VERIFICATION.txt with current URL & SHA256 -$verification = Get-Item -Path .\scripts\chocolatey\algokit\tools\VERIFICATION.txt -$wheel_url = "https://github.com/algorandfoundation/algokit-cli/releases/download/${release_tag}/${wheelFileName}" -$sha_256 = Get-FileHash $wheelFile -(Get-Content $verification).replace("{wheel_url}", $wheel_url).replace("{sha256}", $sha_256.Hash) | Set-Content $verification - -echo "version=$version" | Tee-Object -Append -FilePath $env:GITHUB_OUTPUT -echo "wheelFileName=${wheelFileName}" | Tee-Object -Append -FilePath $env:GITHUB_OUTPUT diff --git a/src/algokit/cli/doctor.py b/src/algokit/cli/doctor.py index ca77c6414..91f28ff74 100644 --- a/src/algokit/cli/doctor.py +++ b/src/algokit/cli/doctor.py @@ -68,7 +68,7 @@ def doctor_command(*, copy_to_clipboard: bool) -> None: ["git", "--version"], missing_help=( [ - "Git required to `run algokit init`; install via `choco install git` if using Chocolatey, ", + "Git required to `run algokit init`; install via `winget install -e --id Git.Git` if using winget,", "or via https://github.com/git-guides/install-git#install-git-on-windows", ] if is_windows @@ -103,7 +103,7 @@ def doctor_command(*, copy_to_clipboard: bool) -> None: "npm": check_dependency(["npm" if not is_windows else "npm.cmd", "--version"]), } if is_windows: - service_outputs["chocolatey"] = check_dependency(["choco", "--version"]) + service_outputs["winget"] = check_dependency(["winget", "--version"]) elif os_type == "Darwin": service_outputs["brew"] = check_dependency(["brew", "--version"]) diff --git a/src/algokit/core/_vendor/auth0/authentication/token_verifier.py b/src/algokit/core/_vendor/auth0/authentication/token_verifier.py index 4b9191fa7..24b4e4329 100644 --- a/src/algokit/core/_vendor/auth0/authentication/token_verifier.py +++ b/src/algokit/core/_vendor/auth0/authentication/token_verifier.py @@ -3,7 +3,6 @@ File ref: https://github.com/auth0/auth0-python/blob/master/auth0/authentication/token_verifier.py """ - from __future__ import annotations import json diff --git a/src/algokit/core/utils.py b/src/algokit/core/utils.py index cf3fdd9c3..8de1d8162 100644 --- a/src/algokit/core/utils.py +++ b/src/algokit/core/utils.py @@ -99,7 +99,7 @@ def find_valid_pipx_command(error_message: str) -> list[str]: return pipx_command # If pipx isn't found in global path or python -m pipx then bail out # this is an exceptional circumstance since pipx should always be present with algokit - # since it's installed with brew / choco as a dependency, and otherwise is used to install algokit + # since it's installed with brew / winget as a dependency, and otherwise is used to install algokit raise click.ClickException(error_message) diff --git a/tests/doctor/test_doctor.py b/tests/doctor/test_doctor.py index cc7055788..137bd01f9 100644 --- a/tests/doctor/test_doctor.py +++ b/tests/doctor/test_doctor.py @@ -43,7 +43,7 @@ def _mock_doctor_dependencies(mocker: MockerFixture) -> None: @pytest.fixture(autouse=True) def _mock_happy_values(proc_mock: ProcMock) -> None: - proc_mock.set_output(["choco", "--version"], ["1.2.2"]) + proc_mock.set_output(["winget", "--version"], ["v1.8.1911"]) proc_mock.set_output(["brew", "--version"], ["Homebrew 3.6.15", "Homebrew/homebrew-core (blah)"]) proc_mock.set_output(["docker", "--version"], ["Docker version 20.10.21, build baeda1f"]) proc_mock.set_output(DOCKER_COMPOSE_VERSION_COMMAND, ['{"version": "v2.12.2"}']) @@ -138,7 +138,6 @@ def test_doctor_with_docker_compose_version_unparseable(proc_mock: ProcMock) -> ALL_COMMANDS = [ - ["choco", "--version"], ["brew", "--version"], ["docker", "--version"], DOCKER_COMPOSE_VERSION_COMMAND, @@ -236,9 +235,7 @@ def test_new_algokit_version_available(request: pytest.FixtureRequest, mocker: M @pytest.mark.mock_platform_system("Windows") def test_doctor_with_weird_values_on_windows(proc_mock: ProcMock) -> None: proc_mock.set_output(["git", "--version"], ["git version 2.31.0.windows.1"]) - proc_mock.set_output( - ["choco"], ["Chocolatey v0.10.15", "choco: Please run 'choco -?' or 'choco -?' for help menu."] - ) + proc_mock.set_output(["winget"], ["v1.8.1911", "Winget v1.8.1911"]) proc_mock.should_fail_on(["npm"]) proc_mock.set_output(["npm.cmd", "--version"], [" 16.17.0 "]) diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt index c51395727..f08da2249 100644 --- a/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt +++ b/tests/doctor/test_doctor.test_doctor_all_commands_bad_exit[windows].approved.txt @@ -16,8 +16,8 @@ DEBUG: Running 'node --version' in '{current_working_directory}' DEBUG: node: I AM A TEAPOT DEBUG: Running 'npm.cmd --version' in '{current_working_directory}' DEBUG: npm.cmd: I AM A TEAPOT -DEBUG: Running 'choco --version' in '{current_working_directory}' -DEBUG: choco: I AM A TEAPOT +DEBUG: Running 'winget --version' in '{current_working_directory}' +DEBUG: winget: v1.8.1911 timestamp: 1990-12-31T10:09:08 AlgoKit: 1.2.3 AlgoKit Python: 3.6.2 (location: /home/me/.local/pipx/venvs/algokit) @@ -40,8 +40,7 @@ node: Command exited with code: -1 I AM A TEAPOT npm: Command exited with code: -1 I AM A TEAPOT -chocolatey: Command exited with code: -1 - I AM A TEAPOT +winget: 1.8.1911 If you are experiencing a problem with AlgoKit, feel free to submit an issue via: https://github.com/algorandfoundation/algokit-cli/issues/new diff --git a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt index 89bcafc8c..bd58ce708 100644 --- a/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt +++ b/tests/doctor/test_doctor.test_doctor_all_commands_not_found[windows].approved.txt @@ -16,8 +16,8 @@ DEBUG: Running 'node --version' in '{current_working_directory}' DEBUG: Command not found DEBUG: Running 'npm.cmd --version' in '{current_working_directory}' DEBUG: Command not found -DEBUG: Running 'choco --version' in '{current_working_directory}' -DEBUG: Command not found +DEBUG: Running 'winget --version' in '{current_working_directory}' +DEBUG: winget: v1.8.1911 timestamp: 1990-12-31T10:09:08 AlgoKit: 1.2.3 AlgoKit Python: 3.6.2 (location: /home/me/.local/pipx/venvs/algokit) @@ -26,7 +26,7 @@ docker: Command not found! `docker` required to run `algokit localnet` command; install via https://docker.io docker compose: Command not found! git: Command not found! - Git required to `run algokit init`; install via `choco install git` if using Chocolatey, + Git required to `run algokit init`; install via `winget install -e --id Git.Git` if using winget, or via https://github.com/git-guides/install-git#install-git-on-windows python: Command not found! python3: Command not found! @@ -42,7 +42,7 @@ node: Command not found! install via `algokit project bootstrap` within project directory, or via: https://nodejs.dev/en/learn/how-to-install-nodejs/ npm: Command not found! -chocolatey: Command not found! +winget: 1.8.1911 If you are experiencing a problem with AlgoKit, feel free to submit an issue via: https://github.com/algorandfoundation/algokit-cli/issues/new diff --git a/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt b/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt index 30782f4c8..8e1ac234b 100644 --- a/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt +++ b/tests/doctor/test_doctor.test_doctor_successful[windows].approved.txt @@ -18,8 +18,8 @@ DEBUG: Running 'node --version' in '{current_working_directory}' DEBUG: node: v18.12.1 DEBUG: Running 'npm.cmd --version' in '{current_working_directory}' DEBUG: npm.cmd: 8.19.2 -DEBUG: Running 'choco --version' in '{current_working_directory}' -DEBUG: choco: 1.2.2 +DEBUG: Running 'winget --version' in '{current_working_directory}' +DEBUG: winget: v1.8.1911 timestamp: 1990-12-31T10:09:08 AlgoKit: 1.2.3 AlgoKit Python: 3.6.2 (location: /home/me/.local/pipx/venvs/algokit) @@ -33,7 +33,7 @@ pipx: 1.1.0 poetry: 1.2.2 node: 18.12.1 npm: 8.19.2 -chocolatey: 1.2.2 +winget: 1.8.1911 If you are experiencing a problem with AlgoKit, feel free to submit an issue via: https://github.com/algorandfoundation/algokit-cli/issues/new diff --git a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt index 5b52b6c89..f6404a0ae 100644 --- a/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt +++ b/tests/doctor/test_doctor.test_doctor_with_weird_values_on_windows.approved.txt @@ -18,9 +18,9 @@ DEBUG: Running 'node --version' in '{current_working_directory}' DEBUG: node: v18.12.1 DEBUG: Running 'npm.cmd --version' in '{current_working_directory}' DEBUG: npm.cmd: 16.17.0 -DEBUG: Running 'choco --version' in '{current_working_directory}' -DEBUG: choco: Chocolatey v0.10.15 -DEBUG: choco: choco: Please run 'choco -?' or 'choco -?' for help menu. +DEBUG: Running 'winget --version' in '{current_working_directory}' +DEBUG: winget: v1.8.1911 +DEBUG: winget: Winget v1.8.1911 timestamp: 1990-12-31T10:09:08 AlgoKit: 1.2.3 AlgoKit Python: 3.6.2 (location: /home/me/.local/pipx/venvs/algokit) @@ -34,7 +34,7 @@ pipx: 1.1.0 poetry: 1.2.2 node: 18.12.1 npm: 16.17.0 -chocolatey: 0.10.15 +winget: 1.8.1911 If you are experiencing a problem with AlgoKit, feel free to submit an issue via: https://github.com/algorandfoundation/algokit-cli/issues/new diff --git a/tests/portability/test_pyinstaller_binary.py b/tests/portability/test_pyinstaller_binary.py index 7566a20e5..5022d3910 100644 --- a/tests/portability/test_pyinstaller_binary.py +++ b/tests/portability/test_pyinstaller_binary.py @@ -38,7 +38,7 @@ def test_non_interactive_algokit_commands( logger.info(f"Command {command} returned {execution_result.stdout}") # Parts of doctor will fail in CI on macOS and windows on github actions since docker isn't available by default - if "doctor" in command and sys.platform in ["darwin", "windows"] and environ.get("CI"): + if "doctor" in command and sys.platform in ["darwin", "windows", "win32"] and environ.get("CI"): exit_codes.append(1) assert execution_result.returncode in exit_codes, f"Command {command} failed with {execution_result.stderr}"