diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..678cb6151 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +docs/ +tests/ +tests_integration/ diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml new file mode 100644 index 000000000..ee1528b73 --- /dev/null +++ b/.github/workflows/test-integration.yml @@ -0,0 +1,211 @@ +name: Integration Tests +on: + push: + branches: + - master + pull_request: null + merge_group: null + + +# Integration tests interact with GitHub resources in the integration test infrastructure and therefore +# cannot run concurrently with other integration tests. +concurrency: + group: cf-scripts-integration-tests + cancel-in-progress: false + +defaults: + run: + shell: bash -leo pipefail {0} + +env: + # Test Instrumentation + # Note: This passes secrets to steps that don't need them. + # We would not do this in a production setting. + GH_TOKEN_STAGING_CONDA_FORGE: ${{ secrets.GH_TOKEN_STAGING_CONDA_FORGE }} + GH_TOKEN_STAGING_BOT_USER: ${{ secrets.GH_TOKEN_STAGING_BOT_USER }} + GH_TOKEN_STAGING_REGRO: ${{ secrets.GH_TOKEN_STAGING_REGRO }} + # Bot + CF_TICK_OVERRIDE_CONDA_FORGE_ORG: conda-forge-bot-staging + CF_TICK_GRAPH_DATA_BACKENDS: file + CF_TICK_CONTAINER_NAME: conda-forge-tick + CF_TICK_CONTAINER_TAG: test + # Deploy to GitHub step + DEPLOY_REPO: regro-staging/cf-graph-countyfair + RUN_URL: "https://github.com/regro/cf-scripts/actions/runs/${{ github.run_id }}" + # Install Bot Code step + CF_GRAPH_REMOTE: https://github.com/regro-staging/cf-graph-countyfair.git + CF_PINNING_REMOTE: https://github.com/conda-forge-bot-staging/conda-forge-pinning-feedstock.git + PRUNE_DOCKER: false + PULL_DOCKER: false + UPDATE_PINNINGS: false + +jobs: + setup-repositories: + name: Set up Integration Tests + runs-on: ubuntu-latest + outputs: + scenario_ids: ${{ steps.setup_repositories.outputs.scenario_ids }} + steps: + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + path: cf-scripts + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3 + + - name: Build Docker Image + uses: docker/build-push-action@16ebe778df0e7752d2cfcbd924afdbbd89c1a755 # v6 + with: + context: cf-scripts + push: false + load: true + tags: conda-forge-tick:test + cache-from: type=gha + cache-to: type=gha,mode=max + outputs: type=docker,dest=/tmp/image.tar + + - name: Upload Docker Image + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4 + with: + name: conda-forge-tick + path: /tmp/image.tar + + - name: setup-micromamba + uses: mamba-org/setup-micromamba@f8b8a1e23a26f60a44c853292711bacfd3eac822 # v1 + with: + environment-file: cf-scripts/conda-lock.yml + environment-name: cf-scripts + condarc-file: cf-scripts/autotick-bot/condarc + + - name: Set up Integration Test Repositories + id: setup_repositories + run: | + pushd cf-scripts + python -m tests_integration.setup_repositories + + run-test-scenario: + name: Run Scenarios + runs-on: ubuntu-latest + needs: setup-repositories + strategy: + matrix: + scenario_id: ${{ fromJson(needs.setup-repositories.outputs.scenario_ids) }} + max-parallel: 1 + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + path: cf-scripts + + - name: Download Docker Image + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + with: + name: conda-forge-tick + path: /tmp + + - name: Load Docker Image + run: | + docker load --input /tmp/image.tar + docker image ls -a + + - name: setup-micromamba + uses: mamba-org/setup-micromamba@f8b8a1e23a26f60a44c853292711bacfd3eac822 # v1 + with: + environment-file: cf-scripts/conda-lock.yml + environment-name: cf-scripts + condarc-file: cf-scripts/autotick-bot/condarc + + - name: Prepare Scenario + run: | + pushd cf-scripts + python -m tests_integration.step_prepare + env: + SCENARIO_ID: ${{ matrix.scenario_id }} + + - name: Start HTTP Proxy + run: | + pushd cf-scripts + ./tests_integration/mock_proxy_start.sh & + sleep 10 + # Install CA Certificate + sudo wget -e use_proxy=yes -e http_proxy=127.0.0.1:8080 -O /usr/local/share/ca-certificates/mitmproxy.crt \ + http://mitm.it/cert/pem + sudo update-ca-certificates + env: + SCENARIO_ID: ${{ matrix.scenario_id }} + PYTHONPATH: ${{ github.workspace }}/cf-scripts + + - name: Install Bot Code + run: | + source cf-scripts/autotick-bot/install_bot_code.sh + env: + # This is the first install, so we need to update the pinnings + UPDATE_PINNINGS: true + + - name: "[Test] Gather all Feedstocks" + run: | + pushd cf-graph + conda-forge-tick --debug gather-all-feedstocks + env: + BOT_TOKEN: ${{ secrets.GH_TOKEN_STAGING_BOT_USER }} + + - name: "[Test] Deploy to GitHub" + run: | + pushd cf-graph + conda-forge-tick --debug deploy-to-github + env: + # note that we need the token scoped for regro-staging + BOT_TOKEN: ${{ secrets.GH_TOKEN_STAGING_REGRO }} + + - name: Reinstall Bot Code + run: | + source cf-scripts/tests_integration/clear_runner.sh + source cf-scripts/autotick-bot/install_bot_code.sh + + - name: "[Test] Make Graph (Nodes and Edges)" + run: | + pushd cf-graph + conda-forge-tick --debug make-graph --update-nodes-and-edges + + - name: "[Test] Deploy to GitHub" + run: | + pushd cf-graph + conda-forge-tick --debug deploy-to-github + env: + BOT_TOKEN: ${{ secrets.GH_TOKEN_STAGING_REGRO }} + + - name: Reinstall Bot Code + run: | + source cf-scripts/tests_integration/clear_runner.sh + source cf-scripts/autotick-bot/install_bot_code.sh + + - name: "[Test] Make Graph (Node Attributes)" + run: | + pushd cf-graph + conda-forge-tick --debug make-graph + + - name: "[Test] Deploy to GitHub" + run: | + pushd cf-graph + conda-forge-tick --debug deploy-to-github + env: + BOT_TOKEN: ${{ secrets.GH_TOKEN_STAGING_REGRO }} + + - name: Reinstall Bot Code + run: | + source cf-scripts/tests_integration/clear_runner.sh + source cf-scripts/autotick-bot/install_bot_code.sh + + - name: "[Test] update_upstream_versions" + run: | + pushd cf-graph + conda-forge-tick --debug update-upstream-versions + + - name: "[Test] Deploy to GitHub" + run: | + pushd cf-graph + conda-forge-tick --debug deploy-to-github + env: + BOT_TOKEN: ${{ secrets.GH_TOKEN_STAGING_REGRO }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 089036aa9..a6fd041d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -74,7 +74,7 @@ jobs: MONGODB_CONNECTION_STRING: "mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000" - name: set up docker buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3 - name: build docker image uses: docker/build-push-action@16ebe778df0e7752d2cfcbd924afdbbd89c1a755 # v6 diff --git a/Dockerfile b/Dockerfile index 9c851ef1d..b05a9041c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,8 @@ RUN conda activate base && \ pip install --no-deps --no-build-isolation -e . && \ cd - && \ conda deactivate && \ - conda deactivate + conda deactivate && \ + rm -rf $AUTOTICK_BOT_DIR/.git # was needed by setuptools-scm # now make the conda user for running tasks and set the user RUN useradd --shell /bin/bash -c "" -m conda diff --git a/README.md b/README.md index 70a7550bf..e2d66b181 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,11 @@ If your migrator needs special configuration, you should write a new factory fun - `CF_TICK_CONTAINER_NAME`: the name of the container to use in the bot, otherwise defaults to `ghcr.io/regro/conda-forge-tick` - `CF_TICK_CONTAINER_TAG`: set this to override the default container tag used in production runs, otherwise the value of `__version__` is used + +For testing purposes, the following additional environment variables are read: + +- `CF_TICK_OVERRIDE_CONDA_FORGE_ORG`: the name of the GitHub organization that contains the feedstocks (defaults to `conda-forge`) + ### Running Tests The test suite relies on `pytest` and uses `docker`. To run the tests, use the following command: diff --git a/autotick-bot/install_bot_code.sh b/autotick-bot/install_bot_code.sh index 1812218c0..a0565efef 100644 --- a/autotick-bot/install_bot_code.sh +++ b/autotick-bot/install_bot_code.sh @@ -1,5 +1,15 @@ #!/bin/bash +# Environment Variables: +# - CF_TICK_CONTAINER_TAG: The tag of the container to use for the bot (optional). +# - CF_GRAPH_REMOTE: The URL to clone the cf-graph repository from (optional). +# - CF_PINNING_REMOTE: The URL to clone the conda-forge-pinning-feedstock repository from (optional). +# - PRUNE_DOCKER: Whether to prune docker images (optional, default is true). +# - PULL_DOCKER: Whether to pull the conda-forge-tick Docker image from GHCR (optional, default is true). +# - UPDATE_PINNINGS: Whether to update the conda-forge-pinnings of conda (optional, default is true). + +set -euxo pipefail + # clean disk space sudo mkdir -p /opt/empty_dir || true for d in \ @@ -14,19 +24,27 @@ for d in \ ; do sudo rsync --stats -a --delete /opt/empty_dir/ $d || true done -sudo apt-get purge -y -f firefox \ - google-chrome-stable \ - microsoft-edge-stable + +# dpkg does not fail if the package is not installed +sudo dpkg --remove firefox \ + google-chrome-stable \ + microsoft-edge-stable sudo apt-get autoremove -y >& /dev/null sudo apt-get autoclean -y >& /dev/null -sudo docker image prune --all --force + +if [[ ${PRUNE_DOCKER:-true} == "true" ]]; then + sudo docker image prune --all --force +fi + df -h git config --global user.name regro-cf-autotick-bot git config --global user.email 36490558+regro-cf-autotick-bot@users.noreply.github.com git config --global pull.rebase false -conda update conda-forge-pinning --yes +if [[ ${UPDATE_PINNINGS:-true} == "true" ]]; then + conda update conda-forge-pinning --yes +fi cd cf-scripts @@ -34,16 +52,20 @@ pip install --no-deps --no-build-isolation -e . cd .. -if [[ "$1" != "--no-clone-graph-and-pinning" ]]; then - git clone --depth=5 https://github.com/regro/cf-graph-countyfair.git cf-graph - git clone --depth=1 https://github.com/conda-forge/conda-forge-pinning-feedstock.git +if [[ "$#" -lt 1 ]] || [[ "$1" != "--no-clone-graph-and-pinning" ]]; then + cf_graph_remote=${CF_GRAPH_REMOTE:-"https://github.com/regro/cf-graph-countyfair.git"} + cf_pinning_remote=${CF_PINNING_REMOTE:-"https://github.com/conda-forge/conda-forge-pinning-feedstock.git"} + git clone --depth=5 "${cf_graph_remote}" cf-graph + git clone --depth=1 "${cf_pinning_remote}" else echo "Skipping cloning of cf-graph and pinning feedstock" fi -bot_tag=$(python -c "import conda_forge_tick; print(conda_forge_tick.__version__)") -docker_tag=${CF_TICK_CONTAINER_TAG:-${bot_tag}} -docker pull ghcr.io/regro/conda-forge-tick:${docker_tag} +if [[ ${PULL_DOCKER:-true} == "true" ]]; then + bot_tag=$(python -c "import conda_forge_tick; print(conda_forge_tick.__version__)") + docker_tag=${CF_TICK_CONTAINER_TAG:-${bot_tag}} + docker pull ghcr.io/regro/conda-forge-tick:${docker_tag} +fi echo -e "\n\n============================================\n============================================" conda info diff --git a/conda-lock.yml b/conda-lock.yml index 4dfe140e8..53ecff1e5 100644 --- a/conda-lock.yml +++ b/conda-lock.yml @@ -3,9 +3,9 @@ metadata: - url: conda-forge used_env_vars: [] content_hash: - linux-64: 74b8ba2455a1c26564be8d99f414d006c68b4448b50a09a2682b6cd487deb834 - osx-64: d4f9ea8b9b5e8c6656029f5f2c36281636e03170c29250e41541975a8d5c78b6 - osx-arm64: 0df568ade8cdfaea2654d2331a61e925288d6d56e0072d96c53941b5e8221271 + linux-64: 6be16ccb6084c3b151af37498d4ccb4ba8a416da24d67bbe0137ac5cb4efb353 + osx-64: 9fc9671934e952cf36afe6b4440ebb766ddec32288d9a0aebd3f200ff5f6e6fc + osx-arm64: be4e55b14e528d043e9718c66660aae94fcd186646a28bd2df0a1b9b6a48882a platforms: - osx-arm64 - linux-64 @@ -200,6 +200,136 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.3-pyhd8ed1ab_0.conda version: 0.2.3 + - category: main + dependencies: + argon2-cffi-bindings: '' + python: '>=3.7' + typing-extensions: '' + hash: + md5: 3afef1f55a1366b4d3b6a0d92e2235e4 + sha256: 130766446f5507bd44df957b6b5c898a8bd98f024bb426ed6cb9ff1ad67fc677 + manager: conda + name: argon2-cffi + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_0.conda + version: 23.1.0 + - category: main + dependencies: + argon2-cffi-bindings: '' + python: '>=3.7' + typing-extensions: '' + hash: + md5: 3afef1f55a1366b4d3b6a0d92e2235e4 + sha256: 130766446f5507bd44df957b6b5c898a8bd98f024bb426ed6cb9ff1ad67fc677 + manager: conda + name: argon2-cffi + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_0.conda + version: 23.1.0 + - category: main + dependencies: + argon2-cffi-bindings: '' + python: '>=3.7' + typing-extensions: '' + hash: + md5: 3afef1f55a1366b4d3b6a0d92e2235e4 + sha256: 130766446f5507bd44df957b6b5c898a8bd98f024bb426ed6cb9ff1ad67fc677 + manager: conda + name: argon2-cffi + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-23.1.0-pyhd8ed1ab_0.conda + version: 23.1.0 + - category: main + dependencies: + cffi: '>=1.0.1' + libgcc-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: de5b16869a430949b02161b04b844a30 + sha256: 104194af519b4e667aa5341068b94b521a791aaaa05ec0091f8f0bdba43a60ac + manager: conda + name: argon2-cffi-bindings + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/argon2-cffi-bindings-21.2.0-py311h459d7ec_4.conda + version: 21.2.0 + - category: main + dependencies: + cffi: '>=1.0.1' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: e2aba0ad0f533ee73f9d4330d2e32549 + sha256: be27659496bcb660fc9c3f5f74128a7bb090336897e9c7cfbcc55ae66f13b8d8 + manager: conda + name: argon2-cffi-bindings + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/argon2-cffi-bindings-21.2.0-py311h2725bcf_4.conda + version: 21.2.0 + - category: main + dependencies: + cffi: '>=1.0.1' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: e9a56c22ca1215ed3a7b6a9e8c4e6f07 + sha256: b9ab23e4f0d615432949d4b93723bd04b3c4aef725aa03b1e993903265c1b975 + manager: conda + name: argon2-cffi-bindings + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/argon2-cffi-bindings-21.2.0-py311heffc1b2_4.conda + version: 21.2.0 + - category: main + dependencies: + python: '>=3.7' + typing_extensions: '>=4' + hash: + md5: 596932155bf88bb6837141550cb721b0 + sha256: 63f85717fd38912a69be5a03d35a648c404cb86843cd4a1302c380c0e7744e30 + manager: conda + name: asgiref + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/asgiref-3.7.2-pyhd8ed1ab_0.conda + version: 3.7.2 + - category: main + dependencies: + python: '>=3.7' + typing_extensions: '>=4' + hash: + md5: 596932155bf88bb6837141550cb721b0 + sha256: 63f85717fd38912a69be5a03d35a648c404cb86843cd4a1302c380c0e7744e30 + manager: conda + name: asgiref + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/asgiref-3.7.2-pyhd8ed1ab_0.conda + version: 3.7.2 + - category: main + dependencies: + python: '>=3.7' + typing_extensions: '>=4' + hash: + md5: 596932155bf88bb6837141550cb721b0 + sha256: 63f85717fd38912a69be5a03d35a648c404cb86843cd4a1302c380c0e7744e30 + manager: conda + name: asgiref + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/asgiref-3.7.2-pyhd8ed1ab_0.conda + version: 3.7.2 - category: main dependencies: libgcc-ng: '>=12' @@ -433,6 +563,51 @@ package: url: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda version: 1.0.0 + - category: main + dependencies: + __glibc: '>=2.17,<3.0.a0' + libgcc-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 0b19fb4accdc6064185d9b96b456ac10 + sha256: 07cbd8a38ed45b8001818dceed20f03cadb3c1b8f373db8c9264fb62a73a52d7 + manager: conda + name: bcrypt + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/bcrypt-4.2.0-py311hb3a8bbb_0.conda + version: 4.2.0 + - category: main + dependencies: + __osx: '>=10.13' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: ee240cb8cff3f0b9ee382bb938fb552c + sha256: a9bf8f0fc0048fd8114f53a1038ddcfd1fe841014e179ca46d258fb52729fe12 + manager: conda + name: bcrypt + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/osx-64/bcrypt-4.2.0-py311h295b1db_0.conda + version: 4.2.0 + - category: main + dependencies: + __osx: '>=11.0' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: e94f7b4bd8b2ca8f6dee59d1ae5a641e + sha256: a116012d350182da76ce0941d4866c04fecbe7806d8cabe886da74c97e70247a + manager: conda + name: bcrypt + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/bcrypt-4.2.0-py311h98c6a39_0.conda + version: 4.2.0 - category: main dependencies: python: '>=3.6' @@ -590,15 +765,15 @@ package: python-dateutil: '>=2.1,<3.0.0' urllib3: '>=1.25.4,!=2.2.0,<3' hash: - md5: f97e5d17f8d0319dd9bfa71e175d8489 - sha256: a107f83d7cf8c8743b5dc7d313088c9cb3f435d55ed14396c4e07dc0677bc9fe + md5: 59a2184f6714e21e3824b8d532b87d17 + sha256: a842fef9dbb315a26c430ca28f486e30e328e1d3aac75a70cf3cd0cf9ac18df7 manager: conda name: botocore optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.3-pyge310_1234567_0.conda - version: 1.35.3 + https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.5-pyge310_1234567_0.conda + version: 1.35.5 - category: main dependencies: jmespath: '>=0.7.1,<2.0.0' @@ -606,15 +781,15 @@ package: python-dateutil: '>=2.1,<3.0.0' urllib3: '>=1.25.4,!=2.2.0,<3' hash: - md5: f97e5d17f8d0319dd9bfa71e175d8489 - sha256: a107f83d7cf8c8743b5dc7d313088c9cb3f435d55ed14396c4e07dc0677bc9fe + md5: 59a2184f6714e21e3824b8d532b87d17 + sha256: a842fef9dbb315a26c430ca28f486e30e328e1d3aac75a70cf3cd0cf9ac18df7 manager: conda name: botocore optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.3-pyge310_1234567_0.conda - version: 1.35.3 + https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.5-pyge310_1234567_0.conda + version: 1.35.5 - category: main dependencies: jmespath: '>=0.7.1,<2.0.0' @@ -622,15 +797,15 @@ package: python-dateutil: '>=2.1,<3.0.0' urllib3: '>=1.25.4,!=2.2.0,<3' hash: - md5: f97e5d17f8d0319dd9bfa71e175d8489 - sha256: a107f83d7cf8c8743b5dc7d313088c9cb3f435d55ed14396c4e07dc0677bc9fe + md5: 59a2184f6714e21e3824b8d532b87d17 + sha256: a842fef9dbb315a26c430ca28f486e30e328e1d3aac75a70cf3cd0cf9ac18df7 manager: conda name: botocore optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.3-pyge310_1234567_0.conda - version: 1.35.3 + https://conda.anaconda.org/conda-forge/noarch/botocore-1.35.5-pyge310_1234567_0.conda + version: 1.35.5 - category: main dependencies: libgcc-ng: '>=12' @@ -638,45 +813,45 @@ package: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: cce9e7c3f1c307f2a5fb08a2922d6164 - sha256: 559093679e9fdb6061b7b80ca0f9a31fe6ffc213f1dae65bc5c82e2cd1a94107 + md5: ced5340f5dc6cff43a80deac8d0e398f + sha256: e2c0a391839914a1b3611b661ebd1736dd747f43a4611254d9333d9db3163ec7 manager: conda name: brotli-python optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hb755f60_1.conda - version: 1.1.0 + https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.0.9-py311ha362b79_9.conda + version: 1.0.9 - category: main dependencies: - libcxx: '>=15.0.7' + libcxx: '>=14.0.6' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: 546fdccabb90492fbaf2da4ffb78f352 - sha256: 0f5e0a7de58006f349220365e32db521a1fe494c37ee455e5ecf05b8fe567dcc + md5: 034ddcc806d421524fbc46778447e87c + sha256: 0d49fcc6eddfc5d87844419b9de4267a83e870331102bf01ca41e404e4374293 manager: conda name: brotli-python optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311hdf8f085_1.conda - version: 1.1.0 + https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.0.9-py311h814d153_9.conda + version: 1.0.9 - category: main dependencies: - libcxx: '>=15.0.7' + libcxx: '>=14.0.6' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: 5e802b015e33447d1283d599d21f052b - sha256: 2d78c79ccf2c17236c52ef217a4c34b762eb7908a6903d94439f787aac1c8f4b + md5: 34c36b315dc70cde887ea8c3991b994d + sha256: a0f54181606c26b754567feac9d0595b7d5de5d199aa15129dcfa3eed10ef3b7 manager: conda name: brotli-python optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311ha891d26_1.conda - version: 1.1.0 + https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.0.9-py311ha397e9f_9.conda + version: 1.0.9 - category: main dependencies: __glibc: '>=2.17,<3.0.a0' @@ -717,40 +892,40 @@ package: - category: main dependencies: __glibc: '>=2.28,<3.0.a0' - libgcc-ng: '>=12' + libgcc-ng: '>=13' hash: - md5: b6927f788e85267beef6cbb292aaebdd - sha256: 3dec5fdb5d1e1758510af0ca163d82ea10109fec8af7d0cd7af38f01068c365b + md5: 0d3c60291342c0c025db231353376dfb + sha256: 2cb24f613eaf2850b1a08f28f967b10d8bd44ef623efa0154dc45eb718776be6 manager: conda name: c-ares optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.33.0-ha66036c_0.conda - version: 1.33.0 + url: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.33.1-heb4867d_0.conda + version: 1.33.1 - category: main dependencies: __osx: '>=10.13' hash: - md5: 3355b2350a1de63943bcd053a4fccd6d - sha256: d1f2429bf3d5d1c7e1a0ce5bf6216b563024169293731a130f7d8a64230b9302 + md5: b31a2de5edfddb308dda802eab2956dc + sha256: 98b0ac09472e6737fc4685147d1755028cc650d428369cbe3cb74ab38b327095 manager: conda name: c-ares optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.33.0-h51dda26_0.conda - version: 1.33.0 + url: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.33.1-h44e7173_0.conda + version: 1.33.1 - category: main dependencies: __osx: '>=11.0' hash: - md5: 47874589be833bd706221ce6897374df - sha256: cc80521ffcc27ddf1362a85acee440bea4aa669f367463cd7d28cb46b497ec55 + md5: 5b69c16ee900aeffcf0103268d708518 + sha256: ad29a9cffa0504cb4bf7605963816feff3c7833f36b050e1e71912d09c38e3f6 manager: conda name: c-ares optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.33.0-h99b78c6_0.conda - version: 1.33.0 + url: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.33.1-hd74edd7_0.conda + version: 1.33.1 - category: main dependencies: {} hash: @@ -1946,39 +2121,39 @@ package: - category: main dependencies: {} hash: - md5: dcd240bb4438c33d6c2dfdd0383f1a9b - sha256: f6399ffc3cc572bd02fa41eba6572c7a5045a1cc4ed6e8f8e1e74f176b2e8ed7 + md5: 0e777d93e1508c6d37c0e650cf7262cd + sha256: 2cab3f6f37e512cf9cce2f3120b91447cc0ddc586276602600d16dee14603513 manager: conda name: conda-forge-pinning optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.23.00.41.48-hd8ed1ab_0.conda - version: 2024.08.23.00.41.48 + https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.26.03.13.26-hd8ed1ab_0.conda + version: 2024.08.26.03.13.26 - category: main dependencies: {} hash: - md5: dcd240bb4438c33d6c2dfdd0383f1a9b - sha256: f6399ffc3cc572bd02fa41eba6572c7a5045a1cc4ed6e8f8e1e74f176b2e8ed7 + md5: 0e777d93e1508c6d37c0e650cf7262cd + sha256: 2cab3f6f37e512cf9cce2f3120b91447cc0ddc586276602600d16dee14603513 manager: conda name: conda-forge-pinning optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.23.00.41.48-hd8ed1ab_0.conda - version: 2024.08.23.00.41.48 + https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.26.03.13.26-hd8ed1ab_0.conda + version: 2024.08.26.03.13.26 - category: main dependencies: {} hash: - md5: dcd240bb4438c33d6c2dfdd0383f1a9b - sha256: f6399ffc3cc572bd02fa41eba6572c7a5045a1cc4ed6e8f8e1e74f176b2e8ed7 + md5: 0e777d93e1508c6d37c0e650cf7262cd + sha256: 2cab3f6f37e512cf9cce2f3120b91447cc0ddc586276602600d16dee14603513 manager: conda name: conda-forge-pinning optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.23.00.41.48-hd8ed1ab_0.conda - version: 2024.08.23.00.41.48 + https://conda.anaconda.org/conda-forge/noarch/conda-forge-pinning-2024.08.26.03.13.26-hd8ed1ab_0.conda + version: 2024.08.26.03.13.26 - category: main dependencies: click: '>=8' @@ -2639,56 +2814,53 @@ package: version: 0.4.1 - category: main dependencies: - __glibc: '>=2.17,<3.0.a0' cffi: '>=1.12' libgcc-ng: '>=12' - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.1.0,<4.0a0' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: f392b3f7a26db16f37cf82996dcfc84d - sha256: 7d5d5c21ba14290ef5ec9238158f5470561be37e03d33d83692ea92325b61fdb + md5: 4df4df92db0b9168c11b72460baec870 + sha256: e0f62e90e664ce33054c7839ee10a975e0a80010c2691e99679319f60decca9f manager: conda name: cryptography optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/linux-64/cryptography-43.0.0-py311hc6616f6_0.conda - version: 43.0.0 + https://conda.anaconda.org/conda-forge/linux-64/cryptography-40.0.2-py311h9b4c7bb_0.conda + version: 40.0.2 - category: main dependencies: - __osx: '>=10.13' cffi: '>=1.12' - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.1.0,<4.0a0' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: 7df8f0c33fc84173530d0607bbe4da8f - sha256: 952118945de705d01b8b11402e82a73fa75c715149fa39575ab8d0bcbb198ba3 + md5: 724b75f84bb1b5d932627d090a527168 + sha256: 2700217dfc3a48e8715d7f4e94870448a37d8e9bb25c4130e83c4807c2f1f3c3 manager: conda name: cryptography optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/osx-64/cryptography-43.0.0-py311h4ba4ffd_0.conda - version: 43.0.0 + https://conda.anaconda.org/conda-forge/osx-64/cryptography-40.0.2-py311h61927ef_0.conda + version: 40.0.2 - category: main dependencies: - __osx: '>=11.0' cffi: '>=1.12' - openssl: '>=3.3.1,<4.0a0' + openssl: '>=3.1.0,<4.0a0' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* hash: - md5: dfa857985da1e336b923776ec67df173 - sha256: 7641049e9aa8785875c6046268c1d6be3095eb586dc9478bbe61e48f6a99a599 + md5: 09ebc937e6441f174bf76ea8f3b789ce + sha256: 2c10a11166f3199795efb6ceceb4dd4557c38f40d568df8af2b829e4597dc360 manager: conda name: cryptography optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-43.0.0-py311hcaeb4ce_0.conda - version: 43.0.0 + https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-40.0.2-py311h507f6e9_0.conda + version: 40.0.2 - category: main dependencies: __glibc: '>=2.17,<3.0.a0' @@ -3118,42 +3290,51 @@ package: version: 1.9.0 - category: main dependencies: + cryptography: '>=2.6,<42.0' + httpcore: '>=0.17.3' + idna: '>=2.1,<4.0' python: '>=3.8.0,<4.0.0' sniffio: '' hash: - md5: 936e6aadb75534384d11d982fab74b61 - sha256: 0d52c878553e569bccfbd96472c1659fb873bc05e95911b457d35982827626fe + md5: a0059139087e108074f4b48b5e94730e + sha256: 11feaf50685db60b7b0b2c3253930fe8c38c6ff1b7a40aafbf37e5a3f4dc97fc manager: conda name: dnspython optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_1.conda + url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_0.conda version: 2.6.1 - category: main dependencies: + cryptography: '>=2.6,<42.0' + httpcore: '>=0.17.3' + idna: '>=2.1,<4.0' python: '>=3.8.0,<4.0.0' sniffio: '' hash: - md5: 936e6aadb75534384d11d982fab74b61 - sha256: 0d52c878553e569bccfbd96472c1659fb873bc05e95911b457d35982827626fe + md5: a0059139087e108074f4b48b5e94730e + sha256: 11feaf50685db60b7b0b2c3253930fe8c38c6ff1b7a40aafbf37e5a3f4dc97fc manager: conda name: dnspython optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_1.conda + url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_0.conda version: 2.6.1 - category: main dependencies: + cryptography: '>=2.6,<42.0' + httpcore: '>=0.17.3' + idna: '>=2.1,<4.0' python: '>=3.8.0,<4.0.0' sniffio: '' hash: - md5: 936e6aadb75534384d11d982fab74b61 - sha256: 0d52c878553e569bccfbd96472c1659fb873bc05e95911b457d35982827626fe + md5: a0059139087e108074f4b48b5e94730e + sha256: 11feaf50685db60b7b0b2c3253930fe8c38c6ff1b7a40aafbf37e5a3f4dc97fc manager: conda name: dnspython optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_1.conda + url: https://conda.anaconda.org/conda-forge/noarch/dnspython-2.6.1-pyhd8ed1ab_0.conda version: 2.6.1 - category: main dependencies: @@ -3191,6 +3372,90 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda version: '0.5' + - category: main + dependencies: + dnspython: '>=2.0.0' + idna: '>=2.0.0' + python: '>=3.7' + hash: + md5: 3067adf57ee658ddf5bfad47b0041ce4 + sha256: ea9e936ed7c49ea6d66fa3554afe31ba311f2a3d5e384d8c38925fda9e37bdb9 + manager: conda + name: email-validator + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/email-validator-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + dnspython: '>=2.0.0' + idna: '>=2.0.0' + python: '>=3.7' + hash: + md5: 3067adf57ee658ddf5bfad47b0041ce4 + sha256: ea9e936ed7c49ea6d66fa3554afe31ba311f2a3d5e384d8c38925fda9e37bdb9 + manager: conda + name: email-validator + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/email-validator-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + dnspython: '>=2.0.0' + idna: '>=2.0.0' + python: '>=3.7' + hash: + md5: 3067adf57ee658ddf5bfad47b0041ce4 + sha256: ea9e936ed7c49ea6d66fa3554afe31ba311f2a3d5e384d8c38925fda9e37bdb9 + manager: conda + name: email-validator + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/email-validator-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + email-validator: '>=2.2.0,<2.2.1.0a0' + hash: + md5: 0214a004f7cf5ac28fc10a390dfc47ee + sha256: 2cbbbe9e0f3872214227c27b8b775dd2296a435c90ef50a7cc69934c329b6c65 + manager: conda + name: email_validator + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/email_validator-2.2.0-hd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + email-validator: '>=2.2.0,<2.2.1.0a0' + hash: + md5: 0214a004f7cf5ac28fc10a390dfc47ee + sha256: 2cbbbe9e0f3872214227c27b8b775dd2296a435c90ef50a7cc69934c329b6c65 + manager: conda + name: email_validator + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/email_validator-2.2.0-hd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + email-validator: '>=2.2.0,<2.2.1.0a0' + hash: + md5: 0214a004f7cf5ac28fc10a390dfc47ee + sha256: 2cbbbe9e0f3872214227c27b8b775dd2296a435c90ef50a7cc69934c329b6c65 + manager: conda + name: email_validator + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/email_validator-2.2.0-hd8ed1ab_0.conda + version: 2.2.0 - category: main dependencies: appdirs: '' @@ -3357,6 +3622,117 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/osx-arm64/expat-2.6.2-hebf3989_0.conda version: 2.6.2 + - category: main + dependencies: + email_validator: '>=2.0.0' + fastapi-cli: '>=0.0.5' + httpx: '>=0.23.0' + jinja2: '>=2.11.2' + pydantic: '>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0' + python: '>=3.8' + python-multipart: '>=0.0.7' + starlette: '>=0.37.2,<0.39.0' + typing-extensions: '>=4.8.0' + uvicorn: '>=0.12.0' + hash: + md5: f74491e68b58995125541f032f25c56f + sha256: b6d0e4894d47a9247b8a24347a2e276fc0443b55b63d5237c9b68601e18564f3 + manager: conda + name: fastapi + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/fastapi-0.112.2-pyhd8ed1ab_0.conda + version: 0.112.2 + - category: main + dependencies: + email_validator: '>=2.0.0' + fastapi-cli: '>=0.0.5' + httpx: '>=0.23.0' + jinja2: '>=2.11.2' + pydantic: '>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0' + python: '>=3.8' + python-multipart: '>=0.0.7' + starlette: '>=0.37.2,<0.39.0' + typing-extensions: '>=4.8.0' + uvicorn: '>=0.12.0' + hash: + md5: f74491e68b58995125541f032f25c56f + sha256: b6d0e4894d47a9247b8a24347a2e276fc0443b55b63d5237c9b68601e18564f3 + manager: conda + name: fastapi + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/fastapi-0.112.2-pyhd8ed1ab_0.conda + version: 0.112.2 + - category: main + dependencies: + email_validator: '>=2.0.0' + fastapi-cli: '>=0.0.5' + httpx: '>=0.23.0' + jinja2: '>=2.11.2' + pydantic: '>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0' + python: '>=3.8' + python-multipart: '>=0.0.7' + starlette: '>=0.37.2,<0.39.0' + typing-extensions: '>=4.8.0' + uvicorn: '>=0.12.0' + hash: + md5: f74491e68b58995125541f032f25c56f + sha256: b6d0e4894d47a9247b8a24347a2e276fc0443b55b63d5237c9b68601e18564f3 + manager: conda + name: fastapi + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/fastapi-0.112.2-pyhd8ed1ab_0.conda + version: 0.112.2 + - category: main + dependencies: + fastapi: '' + python: '>=3.8' + typer: '>=0.12.3' + uvicorn: '>=0.15.0' + hash: + md5: d50cd55f356225d8440741bb911c2a78 + sha256: 72a8b8f55420207086cacf15066e234556669b4f3d6f5f8555a93a0013ed9bc9 + manager: conda + name: fastapi-cli + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/fastapi-cli-0.0.5-pyhd8ed1ab_0.conda + version: 0.0.5 + - category: main + dependencies: + fastapi: '' + python: '>=3.8' + typer: '>=0.12.3' + uvicorn: '>=0.15.0' + hash: + md5: d50cd55f356225d8440741bb911c2a78 + sha256: 72a8b8f55420207086cacf15066e234556669b4f3d6f5f8555a93a0013ed9bc9 + manager: conda + name: fastapi-cli + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/fastapi-cli-0.0.5-pyhd8ed1ab_0.conda + version: 0.0.5 + - category: main + dependencies: + fastapi: '' + python: '>=3.8' + typer: '>=0.12.3' + uvicorn: '>=0.15.0' + hash: + md5: d50cd55f356225d8440741bb911c2a78 + sha256: 72a8b8f55420207086cacf15066e234556669b4f3d6f5f8555a93a0013ed9bc9 + manager: conda + name: fastapi-cli + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/fastapi-cli-0.0.5-pyhd8ed1ab_0.conda + version: 0.0.5 - category: main dependencies: python: '>=3.6' @@ -3471,6 +3847,60 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/flaky-3.8.1-pyhd8ed1ab_0.conda version: 3.8.1 + - category: main + dependencies: + blinker: '>=1.6.2' + click: '>=8.1.3' + importlib-metadata: '>=3.6.0' + itsdangerous: '>=2.1.2' + jinja2: '>=3.1.2' + python: '>=3.8' + werkzeug: '>=2.3.7' + hash: + md5: 9b0d29067484a8dfacfae85b8fba81bc + sha256: 4f84ffdc5471236e8225db86c7508426b46aa2c3802d58ca40b3c3e174533b39 + manager: conda + name: flask + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/flask-2.3.3-pyhd8ed1ab_0.conda + version: 2.3.3 + - category: main + dependencies: + blinker: '>=1.6.2' + click: '>=8.1.3' + importlib-metadata: '>=3.6.0' + itsdangerous: '>=2.1.2' + jinja2: '>=3.1.2' + python: '>=3.8' + werkzeug: '>=2.3.7' + hash: + md5: 9b0d29067484a8dfacfae85b8fba81bc + sha256: 4f84ffdc5471236e8225db86c7508426b46aa2c3802d58ca40b3c3e174533b39 + manager: conda + name: flask + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/flask-2.3.3-pyhd8ed1ab_0.conda + version: 2.3.3 + - category: main + dependencies: + blinker: '>=1.6.2' + click: '>=8.1.3' + importlib-metadata: '>=3.6.0' + itsdangerous: '>=2.1.2' + jinja2: '>=3.1.2' + python: '>=3.8' + werkzeug: '>=2.3.7' + hash: + md5: 9b0d29067484a8dfacfae85b8fba81bc + sha256: 4f84ffdc5471236e8225db86c7508426b46aa2c3802d58ca40b3c3e174533b39 + manager: conda + name: flask + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/flask-2.3.3-pyhd8ed1ab_0.conda + version: 2.3.3 - category: main dependencies: libgcc-ng: '>=12' @@ -5258,38 +5688,38 @@ package: dependencies: python: '>=3.6' hash: - md5: c0cc1420498b17414d8617d0b9f506ca - sha256: 9687ee909ed46169395d4f99a0ee94b80a52f87bed69cd454bb6d37ffeb0ec7b + md5: 99e164522f6bdf23c177c8d9ae63f975 + sha256: 8660d38b272d3713ec8ac5ae918bc3bc80e1b81e1a7d61df554bded71ada6110 manager: conda name: idna optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda - version: '3.7' + url: https://conda.anaconda.org/conda-forge/noarch/idna-3.8-pyhd8ed1ab_0.conda + version: '3.8' - category: main dependencies: python: '>=3.6' hash: - md5: c0cc1420498b17414d8617d0b9f506ca - sha256: 9687ee909ed46169395d4f99a0ee94b80a52f87bed69cd454bb6d37ffeb0ec7b + md5: 99e164522f6bdf23c177c8d9ae63f975 + sha256: 8660d38b272d3713ec8ac5ae918bc3bc80e1b81e1a7d61df554bded71ada6110 manager: conda name: idna optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda - version: '3.7' + url: https://conda.anaconda.org/conda-forge/noarch/idna-3.8-pyhd8ed1ab_0.conda + version: '3.8' - category: main dependencies: python: '>=3.6' hash: - md5: c0cc1420498b17414d8617d0b9f506ca - sha256: 9687ee909ed46169395d4f99a0ee94b80a52f87bed69cd454bb6d37ffeb0ec7b + md5: 99e164522f6bdf23c177c8d9ae63f975 + sha256: 8660d38b272d3713ec8ac5ae918bc3bc80e1b81e1a7d61df554bded71ada6110 manager: conda name: idna optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda - version: '3.7' + url: https://conda.anaconda.org/conda-forge/noarch/idna-3.8-pyhd8ed1ab_0.conda + version: '3.8' - category: main dependencies: python: '>=3.8' @@ -5490,46 +5920,85 @@ package: version: 0.6.1 - category: main dependencies: - more-itertools: '' python: '>=3.8' hash: - md5: 7b756504d362cbad9b73a50a5455cafd - sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + md5: ff7ca04134ee8dde1d7cf491a78ef7c7 + sha256: 4e933e36e9b0401b62ea8fd63393827ebeb4250de77a56687afb387d504523c5 manager: conda - name: jaraco.classes + name: itsdangerous optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda - version: 3.4.0 + https://conda.anaconda.org/conda-forge/noarch/itsdangerous-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 - category: main dependencies: - more-itertools: '' python: '>=3.8' hash: - md5: 7b756504d362cbad9b73a50a5455cafd - sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + md5: ff7ca04134ee8dde1d7cf491a78ef7c7 + sha256: 4e933e36e9b0401b62ea8fd63393827ebeb4250de77a56687afb387d504523c5 manager: conda - name: jaraco.classes + name: itsdangerous optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda - version: 3.4.0 + https://conda.anaconda.org/conda-forge/noarch/itsdangerous-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 - category: main dependencies: - more-itertools: '' python: '>=3.8' hash: - md5: 7b756504d362cbad9b73a50a5455cafd - sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + md5: ff7ca04134ee8dde1d7cf491a78ef7c7 + sha256: 4e933e36e9b0401b62ea8fd63393827ebeb4250de77a56687afb387d504523c5 manager: conda - name: jaraco.classes + name: itsdangerous optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda - version: 3.4.0 + https://conda.anaconda.org/conda-forge/noarch/itsdangerous-2.2.0-pyhd8ed1ab_0.conda + version: 2.2.0 + - category: main + dependencies: + more-itertools: '' + python: '>=3.8' + hash: + md5: 7b756504d362cbad9b73a50a5455cafd + sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + manager: conda + name: jaraco.classes + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + version: 3.4.0 + - category: main + dependencies: + more-itertools: '' + python: '>=3.8' + hash: + md5: 7b756504d362cbad9b73a50a5455cafd + sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + manager: conda + name: jaraco.classes + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + version: 3.4.0 + - category: main + dependencies: + more-itertools: '' + python: '>=3.8' + hash: + md5: 7b756504d362cbad9b73a50a5455cafd + sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + manager: conda + name: jaraco.classes + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + version: 3.4.0 - category: main dependencies: backports.tarfile: '' @@ -5887,6 +6356,45 @@ package: url: https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2023.12.1-pyhd8ed1ab_0.conda version: 2023.12.1 + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 22fb24e365c532a486655aea3980d05b + sha256: 11ece1c36c9299c502f779893d7b0f28ccb6234a6f98d3d71e93455827b1091a + manager: conda + name: kaitaistruct + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/kaitaistruct-0.10-pyhd8ed1ab_0.tar.bz2 + version: '0.10' + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 22fb24e365c532a486655aea3980d05b + sha256: 11ece1c36c9299c502f779893d7b0f28ccb6234a6f98d3d71e93455827b1091a + manager: conda + name: kaitaistruct + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/kaitaistruct-0.10-pyhd8ed1ab_0.tar.bz2 + version: '0.10' + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 22fb24e365c532a486655aea3980d05b + sha256: 11ece1c36c9299c502f779893d7b0f28ccb6234a6f98d3d71e93455827b1091a + manager: conda + name: kaitaistruct + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/kaitaistruct-0.10-pyhd8ed1ab_0.tar.bz2 + version: '0.10' - category: main dependencies: __linux: '' @@ -6073,6 +6581,45 @@ package: url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda version: '2.40' + - category: main + dependencies: + pyasn1: '>=0.4.6' + python: '>=3.6' + hash: + md5: 04487f824694423093e588ee6feadcc0 + sha256: b6e3028306156db76ffa2613ec35d97e565932c5a7dbc8af5c650e34272f08c9 + manager: conda + name: ldap3 + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/ldap3-2.9.1-pyhd8ed1ab_0.tar.bz2 + version: 2.9.1 + - category: main + dependencies: + pyasn1: '>=0.4.6' + python: '>=3.6' + hash: + md5: 04487f824694423093e588ee6feadcc0 + sha256: b6e3028306156db76ffa2613ec35d97e565932c5a7dbc8af5c650e34272f08c9 + manager: conda + name: ldap3 + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/ldap3-2.9.1-pyhd8ed1ab_0.tar.bz2 + version: 2.9.1 + - category: main + dependencies: + pyasn1: '>=0.4.6' + python: '>=3.6' + hash: + md5: 04487f824694423093e588ee6feadcc0 + sha256: b6e3028306156db76ffa2613ec35d97e565932c5a7dbc8af5c650e34272f08c9 + manager: conda + name: ldap3 + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/ldap3-2.9.1-pyhd8ed1ab_0.tar.bz2 + version: 2.9.1 - category: main dependencies: libgcc-ng: '>=12' @@ -6110,6 +6657,49 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.0.0-h9a09cb3_0.tar.bz2 version: 4.0.0 + - category: main + dependencies: + __glibc: '>=2.17,<3.0.a0' + libgcc-ng: '>=12' + libstdcxx-ng: '>=12' + hash: + md5: c48fc56ec03229f294176923c3265c05 + sha256: 945396726cadae174a661ce006e3f74d71dbd719219faf7cc74696b267f7b0b5 + manager: conda + name: libabseil + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_he02047a_1.conda + version: '20240116.2' + - category: main + dependencies: + __osx: '>=10.13' + libcxx: '>=16' + hash: + md5: d6c78ca84abed3fea5f308ac83b8f54e + sha256: 396d18f39d5207ecae06fddcbc6e5f20865718939bc4e0ea9729e13952833aac + manager: conda + name: libabseil + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/libabseil-20240116.2-cxx17_hf036a51_1.conda + version: '20240116.2' + - category: main + dependencies: + __osx: '>=11.0' + libcxx: '>=16' + hash: + md5: f16963d88aed907af8b90878b8d8a05c + sha256: a9517c8683924f4b3b9380cdaa50fdd2009cd8d5f3918c92f64394238189d3cb + manager: conda + name: libabseil + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20240116.2-cxx17_h00cdb27_1.conda + version: '20240116.2' - category: main dependencies: bzip2: '>=1.0.8,<2.0a0' @@ -7460,6 +8050,53 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.43-h091b4b1_0.conda version: 1.6.43 + - category: main + dependencies: + libabseil: '>=20240116.1,<20240117.0a0' + libgcc-ng: '>=12' + libstdcxx-ng: '>=12' + libzlib: '>=1.2.13,<2.0.0a0' + hash: + md5: 6945825cebd2aeb16af4c69d97c32c13 + sha256: 70e0eef046033af2e8d21251a785563ad738ed5281c74e21c31c457780845dcd + manager: conda + name: libprotobuf + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda + version: 4.25.3 + - category: main + dependencies: + __osx: '>=10.13' + libabseil: '>=20240116.1,<20240117.0a0' + libcxx: '>=16' + libzlib: '>=1.2.13,<2.0.0a0' + hash: + md5: 57b7ee4f1fd8573781cfdabaec4a7782 + sha256: 3f126769fb5820387d436370ad48600e05d038a28689fdf9988b64e1059947a8 + manager: conda + name: libprotobuf + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/libprotobuf-4.25.3-h4e4d658_0.conda + version: 4.25.3 + - category: main + dependencies: + libabseil: '>=20240116.1,<20240117.0a0' + libcxx: '>=16' + libzlib: '>=1.2.13,<2.0.0a0' + hash: + md5: 5f70b2b945a9741cba7e6dfe735a02a7 + sha256: d754519abc3ddbdedab2a38d0639170f5347c1573eef80c707f3a8dc5dff706a + manager: conda + name: libprotobuf + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/libprotobuf-4.25.3-hbfab5d5_0.conda + version: 4.25.3 - category: main dependencies: __glibc: '>=2.17,<3.0.a0' @@ -7838,18 +8475,19 @@ package: version: 1.4.0 - category: main dependencies: - libgcc-ng: '>=12' + __glibc: '>=2.17,<3.0.a0' + libgcc-ng: '>=13' pthread-stubs: '' xorg-libxau: '>=1.0.11,<2.0a0' xorg-libxdmcp: '' hash: - md5: 151cba22b85a989c2d6ef9633ffee1e4 - sha256: 7180375f37fd264bb50672a63da94536d4abd81ccec059e932728ae056324b3a + md5: 3601598f0db0470af28985e3e7ad0158 + sha256: 33aa5fc997468b07ab3020b142eacc5479e4e2c2169f467b20ab220f33dd08de manager: conda name: libxcb optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.16-hd590300_0.conda + url: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.16-hb9d3cd8_1.conda version: '1.16' - category: main dependencies: @@ -8373,6 +9011,118 @@ package: url: https://conda.anaconda.org/conda-forge/osx-arm64/menuinst-2.1.2-py311h267d04e_0.conda version: 2.1.2 + - category: main + dependencies: + asgiref: '>=3.2.10,<3.8' + brotli-python: '>=1.0,<1.1' + certifi: '>=2019.9.11' + cryptography: '>=38,<41.1' + flask: '>=1.1.1,<2.4' + h11: '>=0.11,<0.15' + h2: '>=4.1,<5' + hyperframe: '>=6.0,<7' + kaitaistruct: '>=0.10,<0.11' + ldap3: '>=2.8,<2.10' + libgcc-ng: '>=12' + msgpack-python: '>=1.0.0,<1.1.0' + passlib: '>=1.6.5,<1.8' + protobuf: '>=3.14,<5' + publicsuffix2: '>=2.20190812,<3' + pylsqpack: '>=0.3.3,<0.4.0' + pyopenssl: '>=22.1,<23.2' + pyparsing: '>=2.4.2,<3.2' + pyperclip: '>=1.6.0,<1.9' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + ruamel.yaml: '>=0.16,<0.18' + sortedcontainers: '>=2.3,<2.5' + tornado: '>=6.2,<7' + wsproto: '>=1.0,<1.3' + zstandard: '>=0.11,<0.22' + hash: + md5: 286dfce5e12ff1d688b43bb7e11fb6bb + sha256: f199c24c7e77788191d66a8ff09eb3f31896f6c6dc1185dfe2fac6f43d94b859 + manager: conda + name: mitmproxy + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/mitmproxy-10.1.0-py311h46250e7_1.conda + version: 10.1.0 + - category: main + dependencies: + asgiref: '>=3.2.10,<3.8' + brotli-python: '>=1.0,<1.1' + certifi: '>=2019.9.11' + cryptography: '>=38,<41.1' + flask: '>=1.1.1,<2.4' + h11: '>=0.11,<0.15' + h2: '>=4.1,<5' + hyperframe: '>=6.0,<7' + kaitaistruct: '>=0.10,<0.11' + ldap3: '>=2.8,<2.10' + msgpack-python: '>=1.0.0,<1.1.0' + passlib: '>=1.6.5,<1.8' + protobuf: '>=3.14,<5' + publicsuffix2: '>=2.20190812,<3' + pylsqpack: '>=0.3.3,<0.4.0' + pyopenssl: '>=22.1,<23.2' + pyparsing: '>=2.4.2,<3.2' + pyperclip: '>=1.6.0,<1.9' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + ruamel.yaml: '>=0.16,<0.18' + sortedcontainers: '>=2.3,<2.5' + tornado: '>=6.2,<7' + wsproto: '>=1.0,<1.3' + zstandard: '>=0.11,<0.22' + hash: + md5: a7d334de4fad6050bfe8898c69d98111 + sha256: cdf2b6bd3543f3b3ef466eb1b0b5b1488c482cddbd34c112b0d1b6a46b263e99 + manager: conda + name: mitmproxy + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/mitmproxy-10.1.0-py311h5e0f0e4_0.conda + version: 10.1.0 + - category: main + dependencies: + asgiref: '>=3.2.10,<3.8' + brotli-python: '>=1.0,<1.1' + certifi: '>=2019.9.11' + cryptography: '>=38,<41.1' + flask: '>=1.1.1,<2.4' + h11: '>=0.11,<0.15' + h2: '>=4.1,<5' + hyperframe: '>=6.0,<7' + kaitaistruct: '>=0.10,<0.11' + ldap3: '>=2.8,<2.10' + msgpack-python: '>=1.0.0,<1.1.0' + passlib: '>=1.6.5,<1.8' + protobuf: '>=3.14,<5' + publicsuffix2: '>=2.20190812,<3' + pylsqpack: '>=0.3.3,<0.4.0' + pyopenssl: '>=22.1,<23.2' + pyparsing: '>=2.4.2,<3.2' + pyperclip: '>=1.6.0,<1.9' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + ruamel.yaml: '>=0.16,<0.18' + sortedcontainers: '>=2.3,<2.5' + tornado: '>=6.2,<7' + wsproto: '>=1.0,<1.3' + zstandard: '>=0.11,<0.22' + hash: + md5: 0059bf2757092ddcd33e9da3343f8816 + sha256: 0c54d7ca50d4b46c937ceb67fa8702d7cd249b4789d30af590a134f9094336bf + manager: conda + name: mitmproxy + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/mitmproxy-10.1.0-py311h94f323b_0.conda + version: 10.1.0 - category: main dependencies: python: '>=3.8' @@ -8726,41 +9476,41 @@ package: dependencies: __glibc: '>=2.17,<3.0.a0' ca-certificates: '' - libgcc-ng: '>=12' + libgcc-ng: '>=13' hash: - md5: e1b454497f9f7c1147fdde4b53f1b512 - sha256: b294b3cc706ad1048cdb514f0db3da9f37ae3fcc0c53a7104083dd0918adb200 + md5: 6c566a46baae794daf34775d41eb180a + sha256: 9e27441b273a7cf9071f6e88ba9ad565d926d8083b154c64a74b99fba167b137 manager: conda name: openssl optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-h4bc722e_2.conda + url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-hb9d3cd8_3.conda version: 3.3.1 - category: main dependencies: __osx: '>=10.13' ca-certificates: '' hash: - md5: 3f3dbeedbee31e257866407d9dea1ff5 - sha256: 3cb0c05fbfd8cdb9b767396fc0e0af2d78eb4d68592855481254104330d4a4eb + md5: ad8c8c9556a701817bd1aca75a302e96 + sha256: 63921822fbb66337e0fd50b2a07412583fbe7783bc92c663bdf93c9a09026fdc manager: conda name: openssl optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.1-h87427d6_2.conda + url: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.1-hd23fc13_3.conda version: 3.3.1 - category: main dependencies: __osx: '>=11.0' ca-certificates: '' hash: - md5: 9b551a504c1cc8f8b7b22c01814da8ba - sha256: dd7d988636f74473ebdfe15e05c5aabdb53a1d2a846c839d62289b0c37f81548 + md5: 644904d696d83c0ac78d594e0cf09f66 + sha256: 9dd1ee7a8c21ff4fcbb98e9d0be0e83e5daf8a555c73589ad9e3046966b72e5e manager: conda name: openssl optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.1-hfb2fe0b_2.conda + url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.1-h8359307_3.conda version: 3.3.1 - category: main dependencies: @@ -8942,6 +9692,51 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda version: 1.4.2 + - category: main + dependencies: + argon2-cffi: '>=19.2.0' + bcrypt: '>=3.1.0' + cryptography: '' + python: '>=3.8' + hash: + md5: b227694201828eba9a4c6b6d289a72dd + sha256: 22b0c524eb3f5d63ef7fbc7bff5a636b14d21abeaf9541c1781087c4099bfec7 + manager: conda + name: passlib + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/passlib-1.7.4-pyhd8ed1ab_1.conda + version: 1.7.4 + - category: main + dependencies: + argon2-cffi: '>=19.2.0' + bcrypt: '>=3.1.0' + cryptography: '' + python: '>=3.8' + hash: + md5: b227694201828eba9a4c6b6d289a72dd + sha256: 22b0c524eb3f5d63ef7fbc7bff5a636b14d21abeaf9541c1781087c4099bfec7 + manager: conda + name: passlib + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/passlib-1.7.4-pyhd8ed1ab_1.conda + version: 1.7.4 + - category: main + dependencies: + argon2-cffi: '>=19.2.0' + bcrypt: '>=3.1.0' + cryptography: '' + python: '>=3.8' + hash: + md5: b227694201828eba9a4c6b6d289a72dd + sha256: 22b0c524eb3f5d63ef7fbc7bff5a636b14d21abeaf9541c1781087c4099bfec7 + manager: conda + name: passlib + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/passlib-1.7.4-pyhd8ed1ab_1.conda + version: 1.7.4 - category: main dependencies: python: '>=2.7' @@ -9507,6 +10302,62 @@ package: url: https://conda.anaconda.org/conda-forge/noarch/progressbar2-4.4.2-pyhd8ed1ab_0.conda version: 4.4.2 + - category: main + dependencies: + libabseil: '>=20240116.1,<20240117.0a0' + libgcc-ng: '>=12' + libprotobuf: '>=4.25.3,<4.25.4.0a0' + libstdcxx-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + setuptools: '' + hash: + md5: fe6c263e6bd0ec098995b7cd176b0f95 + sha256: 90eccef0b175777de1d179fc66e47af47ad0ae2bb9a949a08cc1d42b8b1ec57f + manager: conda + name: protobuf + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/protobuf-4.25.3-py311h7b78aeb_0.conda + version: 4.25.3 + - category: main + dependencies: + __osx: '>=10.13' + libabseil: '>=20240116.1,<20240117.0a0' + libcxx: '>=16' + libprotobuf: '>=4.25.3,<4.25.4.0a0' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + setuptools: '' + hash: + md5: e256d9dfa0a194550d15be2aea20de3b + sha256: 7543f0145d70ccf7144ef46794ef4271c3c2057394aee3010ba4b4241a6742a6 + manager: conda + name: protobuf + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/protobuf-4.25.3-py311h01b5fa2_0.conda + version: 4.25.3 + - category: main + dependencies: + libabseil: '>=20240116.1,<20240117.0a0' + libcxx: '>=16' + libprotobuf: '>=4.25.3,<4.25.4.0a0' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + setuptools: '' + hash: + md5: 5ab4584ffe61409531b56360d146301a + sha256: 5b92958d79445b82258d23725df338fc2d8e5791e8dfd853d87d132aab9425cc + manager: conda + name: protobuf + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/protobuf-4.25.3-py311hea19e3d_0.conda + version: 4.25.3 - category: main dependencies: libgcc-ng: '>=12' @@ -9605,28 +10456,67 @@ package: version: 0.7.0 - category: main dependencies: - libgcc-ng: '>=12' - liblief: 0.14.1 - libstdcxx-ng: '>=12' - python: '>=3.11,<3.12.0a0' - python_abi: 3.11.* + python: '>=3.6' hash: - md5: b580153e3b54da2b04d701025998a3c9 - sha256: ae3ca16770b295b2fe598f4c049e685f52e60c51535151f1803326649a96c54a + md5: efb961f1a6ccbb670fd48d692580dce9 + sha256: 7c7685c6890b893fdcc1a05205d21e17d09835815b146b642bf847447d92bd29 manager: conda - name: py-lief + name: publicsuffix2 optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/linux-64/py-lief-0.14.1-py311h4332511_1.conda - version: 0.14.1 + https://conda.anaconda.org/conda-forge/noarch/publicsuffix2-2.20191221-pyhd8ed1ab_0.tar.bz2 + version: '2.20191221' - category: main dependencies: - __osx: '>=10.13' - libcxx: '>=16' - liblief: 0.14.1 - python: '>=3.11,<3.12.0a0' - python_abi: 3.11.* + python: '>=3.6' + hash: + md5: efb961f1a6ccbb670fd48d692580dce9 + sha256: 7c7685c6890b893fdcc1a05205d21e17d09835815b146b642bf847447d92bd29 + manager: conda + name: publicsuffix2 + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/publicsuffix2-2.20191221-pyhd8ed1ab_0.tar.bz2 + version: '2.20191221' + - category: main + dependencies: + python: '>=3.6' + hash: + md5: efb961f1a6ccbb670fd48d692580dce9 + sha256: 7c7685c6890b893fdcc1a05205d21e17d09835815b146b642bf847447d92bd29 + manager: conda + name: publicsuffix2 + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/publicsuffix2-2.20191221-pyhd8ed1ab_0.tar.bz2 + version: '2.20191221' + - category: main + dependencies: + libgcc-ng: '>=12' + liblief: 0.14.1 + libstdcxx-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: b580153e3b54da2b04d701025998a3c9 + sha256: ae3ca16770b295b2fe598f4c049e685f52e60c51535151f1803326649a96c54a + manager: conda + name: py-lief + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/py-lief-0.14.1-py311h4332511_1.conda + version: 0.14.1 + - category: main + dependencies: + __osx: '>=10.13' + libcxx: '>=16' + liblief: 0.14.1 + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* hash: md5: 9a39b1dd56bbb1b1c4bef604029ea9cc sha256: 6be49d5a69b75e85a81d9dd05f6a52ab585df1defbbf81b45b1d0038e13dded4 @@ -9702,6 +10592,42 @@ package: url: https://conda.anaconda.org/conda-forge/osx-arm64/py-rattler-0.6.3-py311hcaeb4ce_0.conda version: 0.6.3 + - category: main + dependencies: + python: '!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,!=3.5' + hash: + md5: d528d00a110a974e75aa6db6a4f04dc7 + sha256: 9b54bf52c76bb7365ceb36315258011b8c603fe00f568d4bbff8bc77c7ffcfdb + manager: conda + name: pyasn1 + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyasn1-0.6.0-pyhd8ed1ab_0.conda + version: 0.6.0 + - category: main + dependencies: + python: '!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,!=3.5' + hash: + md5: d528d00a110a974e75aa6db6a4f04dc7 + sha256: 9b54bf52c76bb7365ceb36315258011b8c603fe00f568d4bbff8bc77c7ffcfdb + manager: conda + name: pyasn1 + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyasn1-0.6.0-pyhd8ed1ab_0.conda + version: 0.6.0 + - category: main + dependencies: + python: '!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,!=3.5' + hash: + md5: d528d00a110a974e75aa6db6a4f04dc7 + sha256: 9b54bf52c76bb7365ceb36315258011b8c603fe00f568d4bbff8bc77c7ffcfdb + manager: conda + name: pyasn1 + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/pyasn1-0.6.0-pyhd8ed1ab_0.conda + version: 0.6.0 - category: main dependencies: {} hash: @@ -10164,6 +11090,49 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/pylev-1.4.0-pyhd8ed1ab_0.tar.bz2 version: 1.4.0 + - category: main + dependencies: + libgcc-ng: '>=12' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 43123e3973f57ff8ab79d4f0c8da107e + sha256: ead2ad1c715834343751fd2ca3a12c396f2517d3024d2909a408b9eacdc9f1a6 + manager: conda + name: pylsqpack + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/pylsqpack-0.3.18-py311h459d7ec_0.conda + version: 0.3.18 + - category: main + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 46afc59d2fdd80da674221560250ad74 + sha256: be013621b9bd07e18478a4b234d2b0785f42938ab2955361cc42cbf0c7d94df1 + manager: conda + name: pylsqpack + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/pylsqpack-0.3.18-py311he705e18_0.conda + version: 0.3.18 + - category: main + dependencies: + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 7c4076675a548692890f37d2d05d9727 + sha256: 1b932153db9ae0a89dc618ca50b4de8a923d6ad43be56061bc402c8a78c69db4 + manager: conda + name: pylsqpack + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/pylsqpack-0.3.18-py311h05b510d_0.conda + version: 0.3.18 - category: main dependencies: dnspython: <3.0.0,>=1.16.0 @@ -10308,6 +11277,195 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/pynamodb-6.0.1-pyhd8ed1ab_0.conda version: 6.0.1 + - category: main + dependencies: + __osx: '>=10.13' + libffi: '>=3.4,<4.0a0' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + setuptools: '' + hash: + md5: 5bce9e98557971559e7c2e672c6772fe + sha256: 00321f83e0079164e3c220b0b8311c1397dac34e8a209c3300c1cae04b1796ed + manager: conda + name: pyobjc-core + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/pyobjc-core-10.3.1-py311h9d23797_0.conda + version: 10.3.1 + - category: main + dependencies: + __osx: '>=11.0' + libffi: '>=3.4,<4.0a0' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + setuptools: '' + hash: + md5: 03b8f7f2cd5efcebac78a17f8ae8c0d2 + sha256: 7d52a7ee1fa28ed97acd33ad29407aca29e652c4588e15a98360b729a4155ec7 + manager: conda + name: pyobjc-core + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-10.3.1-py311h5f135c3_0.conda + version: 10.3.1 + - category: main + dependencies: + __osx: '>=10.13' + libffi: '>=3.4,<4.0a0' + pyobjc-core: 10.3.1.* + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 557ec4f240ee3f8944ae1b3015ef36dd + sha256: 8cc6a36d71affa4354ed5184ebafe1144f5a0a4add37f4410ff4ea422695f47c + manager: conda + name: pyobjc-framework-cocoa + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/pyobjc-framework-cocoa-10.3.1-py311h9d23797_0.conda + version: 10.3.1 + - category: main + dependencies: + __osx: '>=11.0' + libffi: '>=3.4,<4.0a0' + pyobjc-core: 10.3.1.* + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: a0541fa0e67858765b21be323626f5b0 + sha256: 80c5cc1941af44446ee007a6c7c98c642307ae968fd70f7f5bf6ebd0ec311fd5 + manager: conda + name: pyobjc-framework-cocoa + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-framework-cocoa-10.3.1-py311h5f135c3_0.conda + version: 10.3.1 + - category: main + dependencies: + cryptography: '>=38.0.0,<41' + python: '>=3.6' + hash: + md5: 0b34aa3ab7e7ccb1765a03dd9ed29938 + sha256: 458428cb867f70f2af2a4ed59d382291ea3eb3f10490196070a15d1d71d5432a + manager: conda + name: pyopenssl + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.1.1-pyhd8ed1ab_0.conda + version: 23.1.1 + - category: main + dependencies: + cryptography: '>=38.0.0,<41' + python: '>=3.6' + hash: + md5: 0b34aa3ab7e7ccb1765a03dd9ed29938 + sha256: 458428cb867f70f2af2a4ed59d382291ea3eb3f10490196070a15d1d71d5432a + manager: conda + name: pyopenssl + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.1.1-pyhd8ed1ab_0.conda + version: 23.1.1 + - category: main + dependencies: + cryptography: '>=38.0.0,<41' + python: '>=3.6' + hash: + md5: 0b34aa3ab7e7ccb1765a03dd9ed29938 + sha256: 458428cb867f70f2af2a4ed59d382291ea3eb3f10490196070a15d1d71d5432a + manager: conda + name: pyopenssl + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.1.1-pyhd8ed1ab_0.conda + version: 23.1.1 + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 4d91352a50949d049cf9714c8563d433 + sha256: 8714a83f1aeac278b3eb33c7cb880c95c9a5924e7a5feeb9e87e7d0837afa085 + manager: conda + name: pyparsing + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.4-pyhd8ed1ab_0.conda + version: 3.1.4 + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 4d91352a50949d049cf9714c8563d433 + sha256: 8714a83f1aeac278b3eb33c7cb880c95c9a5924e7a5feeb9e87e7d0837afa085 + manager: conda + name: pyparsing + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.4-pyhd8ed1ab_0.conda + version: 3.1.4 + - category: main + dependencies: + python: '>=3.6' + hash: + md5: 4d91352a50949d049cf9714c8563d433 + sha256: 8714a83f1aeac278b3eb33c7cb880c95c9a5924e7a5feeb9e87e7d0837afa085 + manager: conda + name: pyparsing + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.1.4-pyhd8ed1ab_0.conda + version: 3.1.4 + - category: main + dependencies: + __linux: '' + python: '>=3.6' + xclip: '' + xsel: '' + hash: + md5: 2acdfb68ee42274329494c93fcf92ce6 + sha256: c4404821044f2fd2c33a1159d525368672d04e369d8c16b8cc8488a4a8bd5be5 + manager: conda + name: pyperclip + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyperclip-1.8.2-pyha804496_3.conda + version: 1.8.2 + - category: main + dependencies: + __osx: '' + pyobjc-framework-cocoa: '' + python: '>=3.6' + hash: + md5: aca7616a492c45b55b97d1b4e882ebea + sha256: 026d26b5e624de4b1f1c359224f57421b7ceaaecba4ffe265b65ef6d1253f4cb + manager: conda + name: pyperclip + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/pyperclip-1.8.2-pyh534df25_3.conda + version: 1.8.2 + - category: main + dependencies: + __osx: '' + pyobjc-framework-cocoa: '' + python: '>=3.6' + hash: + md5: aca7616a492c45b55b97d1b4e882ebea + sha256: 026d26b5e624de4b1f1c359224f57421b7ceaaecba4ffe265b65ef6d1253f4cb + manager: conda + name: pyperclip + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/pyperclip-1.8.2-pyh534df25_3.conda + version: 1.8.2 - category: main dependencies: python: '>=3.7' @@ -10927,6 +12085,45 @@ package: url: https://conda.anaconda.org/conda-forge/osx-arm64/python-libarchive-c-5.1-py311h267d04e_0.conda version: '5.1' + - category: main + dependencies: + python: '>=3.7' + hash: + md5: 0eef653965f0fed2013924d08089f371 + sha256: 026467128031bd667c4a32555ae07e922d5caed257e4815c44e7338887bbd56a + manager: conda + name: python-multipart + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/python-multipart-0.0.9-pyhd8ed1ab_0.conda + version: 0.0.9 + - category: main + dependencies: + python: '>=3.7' + hash: + md5: 0eef653965f0fed2013924d08089f371 + sha256: 026467128031bd667c4a32555ae07e922d5caed257e4815c44e7338887bbd56a + manager: conda + name: python-multipart + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/python-multipart-0.0.9-pyhd8ed1ab_0.conda + version: 0.0.9 + - category: main + dependencies: + python: '>=3.7' + hash: + md5: 0eef653965f0fed2013924d08089f371 + sha256: 026467128031bd667c4a32555ae07e922d5caed257e4815c44e7338887bbd56a + manager: conda + name: python-multipart + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/python-multipart-0.0.9-pyhd8ed1ab_0.conda + version: 0.0.9 - category: main dependencies: __glibc: '>=2.17,<3.0.a0' @@ -11714,46 +12911,49 @@ package: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* ruamel.yaml.clib: '>=0.1.2' + setuptools: '' hash: - md5: 4dccc0bc3bb4d6e5c30bccbd053c4f90 - sha256: b7056cf0f680a70c24d0a9addea6e8b640bfeafda4c37887e276331757404da0 + md5: 59518a18bdf00ee4379797459d2c76ee + sha256: b33e0e83f834b948ce5c77c0df727b6cd027a388c3b4e4498b34b83751ba7c05 manager: conda name: ruamel.yaml optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.6-py311h459d7ec_0.conda - version: 0.18.6 + https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.17.40-py311h459d7ec_0.conda + version: 0.17.40 - category: main dependencies: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* ruamel.yaml.clib: '>=0.1.2' + setuptools: '' hash: - md5: 7a3e388f29ca1862754f89b6d79de335 - sha256: 64b13898feefe6b98b776a8a0fff05163dad116c643b946a611ae895edcf435b + md5: 4796cc1d45c88ace8f5bb7950167a568 + sha256: 0260c295cdfae417f107fe2fae66bae4eb260195885d81d8b1cd4fc6d81c849b manager: conda name: ruamel.yaml optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.18.6-py311he705e18_0.conda - version: 0.18.6 + https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.40-py311he705e18_0.conda + version: 0.17.40 - category: main dependencies: python: '>=3.11,<3.12.0a0' python_abi: 3.11.* ruamel.yaml.clib: '>=0.1.2' + setuptools: '' hash: - md5: d2a62ffc98713af809060950a6c1d107 - sha256: 7ed21c406b18c0ae1c3f6815afe5d7dcfddc374a0ac212fd9f203767d0a18ad4 + md5: 640b6933c680860877b32a4c11076ab9 + sha256: bf44774cbd03eb8d396a078b4af1b194f8600f8ca7ea7ca0e3d61dc16b400cb4 manager: conda name: ruamel.yaml optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.18.6-py311h05b510d_0.conda - version: 0.18.6 + https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.17.40-py311h05b510d_0.conda + version: 0.17.40 - category: main dependencies: libgcc-ng: '>=12' @@ -12422,6 +13622,51 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda version: '2.5' + - category: main + dependencies: + anyio: <5,>=3.4.0 + python: '>=3.8' + typing_extensions: '>=3.10.0' + hash: + md5: 4514ed54fc1b95a9d1f4d7cb126601a2 + sha256: a9f2e202ba06514702590dd864cbcdd87b3d7a08b535e6b680798f39a6432356 + manager: conda + name: starlette + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/noarch/starlette-0.38.2-pyhd8ed1ab_0.conda + version: 0.38.2 + - category: main + dependencies: + anyio: <5,>=3.4.0 + python: '>=3.8' + typing_extensions: '>=3.10.0' + hash: + md5: 4514ed54fc1b95a9d1f4d7cb126601a2 + sha256: a9f2e202ba06514702590dd864cbcdd87b3d7a08b535e6b680798f39a6432356 + manager: conda + name: starlette + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/noarch/starlette-0.38.2-pyhd8ed1ab_0.conda + version: 0.38.2 + - category: main + dependencies: + anyio: <5,>=3.4.0 + python: '>=3.8' + typing_extensions: '>=3.10.0' + hash: + md5: 4514ed54fc1b95a9d1f4d7cb126601a2 + sha256: a9f2e202ba06514702590dd864cbcdd87b3d7a08b535e6b680798f39a6432356 + manager: conda + name: starlette + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/noarch/starlette-0.38.2-pyhd8ed1ab_0.conda + version: 0.38.2 - category: main dependencies: python: '>=3.7' @@ -13032,132 +14277,132 @@ package: - category: main dependencies: python: '>=3.7' - typer-slim-standard: 0.12.4 + typer-slim-standard: 0.12.5 hash: - md5: f905d31da5631dfb35e0895a7d8446f8 - sha256: 0662dabe0c77a7ab86db8a3b2dc6af8e0efa542da48423718c9119fe8acac1ba + md5: be70216cc1a5fe502c849676baabf498 + sha256: da9ff9e27c5fa8268c2d5898335485a897d9496eef3b5b446cd9387a89d168de manager: conda name: typer optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: python: '>=3.7' - typer-slim-standard: 0.12.4 + typer-slim-standard: 0.12.5 hash: - md5: f905d31da5631dfb35e0895a7d8446f8 - sha256: 0662dabe0c77a7ab86db8a3b2dc6af8e0efa542da48423718c9119fe8acac1ba + md5: be70216cc1a5fe502c849676baabf498 + sha256: da9ff9e27c5fa8268c2d5898335485a897d9496eef3b5b446cd9387a89d168de manager: conda name: typer optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: python: '>=3.7' - typer-slim-standard: 0.12.4 + typer-slim-standard: 0.12.5 hash: - md5: f905d31da5631dfb35e0895a7d8446f8 - sha256: 0662dabe0c77a7ab86db8a3b2dc6af8e0efa542da48423718c9119fe8acac1ba + md5: be70216cc1a5fe502c849676baabf498 + sha256: da9ff9e27c5fa8268c2d5898335485a897d9496eef3b5b446cd9387a89d168de manager: conda name: typer optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + url: https://conda.anaconda.org/conda-forge/noarch/typer-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: click: '>=8.0.0' python: '>=3.7' typing_extensions: '>=3.7.4.3' hash: - md5: c68f47e7b02694f3d0f8eea00b5d9a17 - sha256: c3042feb1f70b008759a09a7a010e617294dcf43cb111c13ec48546ed3e92b74 + md5: a46aa56c0ca7cc2bd38baffc2686f0a6 + sha256: 7be1876627495047f3f07c52c93ddc2ae2017b93affe58110a5474e5ebcb2662 manager: conda name: typer-slim optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: click: '>=8.0.0' python: '>=3.7' typing_extensions: '>=3.7.4.3' hash: - md5: c68f47e7b02694f3d0f8eea00b5d9a17 - sha256: c3042feb1f70b008759a09a7a010e617294dcf43cb111c13ec48546ed3e92b74 + md5: a46aa56c0ca7cc2bd38baffc2686f0a6 + sha256: 7be1876627495047f3f07c52c93ddc2ae2017b93affe58110a5474e5ebcb2662 manager: conda name: typer-slim optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: click: '>=8.0.0' python: '>=3.7' typing_extensions: '>=3.7.4.3' hash: - md5: c68f47e7b02694f3d0f8eea00b5d9a17 - sha256: c3042feb1f70b008759a09a7a010e617294dcf43cb111c13ec48546ed3e92b74 + md5: a46aa56c0ca7cc2bd38baffc2686f0a6 + sha256: 7be1876627495047f3f07c52c93ddc2ae2017b93affe58110a5474e5ebcb2662 manager: conda name: typer-slim optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.4-pyhd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-0.12.5-pyhd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: rich: '' shellingham: '' - typer-slim: 0.12.4 + typer-slim: 0.12.5 hash: - md5: 7ad257f55c47dde09e8cce723de7ba23 - sha256: 14d484828bfb1f080f0fff92205c495f18cfbd8fd23af89cf74989b7ba8d9ad0 + md5: 2dc1ee4046de0692077e9aa9ba351d36 + sha256: bb298b116159ec1085f6b29eaeb982006651a0997eda08de8b70cfb6177297f3 manager: conda name: typer-slim-standard optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.4-hd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.5-hd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: rich: '' shellingham: '' - typer-slim: 0.12.4 + typer-slim: 0.12.5 hash: - md5: 7ad257f55c47dde09e8cce723de7ba23 - sha256: 14d484828bfb1f080f0fff92205c495f18cfbd8fd23af89cf74989b7ba8d9ad0 + md5: 2dc1ee4046de0692077e9aa9ba351d36 + sha256: bb298b116159ec1085f6b29eaeb982006651a0997eda08de8b70cfb6177297f3 manager: conda name: typer-slim-standard optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.4-hd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.5-hd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: rich: '' shellingham: '' - typer-slim: 0.12.4 + typer-slim: 0.12.5 hash: - md5: 7ad257f55c47dde09e8cce723de7ba23 - sha256: 14d484828bfb1f080f0fff92205c495f18cfbd8fd23af89cf74989b7ba8d9ad0 + md5: 2dc1ee4046de0692077e9aa9ba351d36 + sha256: bb298b116159ec1085f6b29eaeb982006651a0997eda08de8b70cfb6177297f3 manager: conda name: typer-slim-standard optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.4-hd8ed1ab_0.conda - version: 0.12.4 + https://conda.anaconda.org/conda-forge/noarch/typer-slim-standard-0.12.5-hd8ed1ab_0.conda + version: 0.12.5 - category: main dependencies: typing_extensions: 4.12.2 @@ -13447,40 +14692,88 @@ package: libgcc-ng: '>=13' libstdcxx-ng: '>=13' hash: - md5: a1573478950588d2861a61e2898e47d2 - sha256: f3562aef27092447ec1ac3b19abce9fe4be187a2e4f8979ce1dbe02045f9799f + md5: f8a101f4a404ee2b8a72233d41e30235 + sha256: 2beb3663c71f38ef4f072f7c548797f31e03e2e8ff3aa16c529550279ce8b50c manager: conda name: uv optional: false platform: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/uv-0.3.1-h0f3a69f_0.conda - version: 0.3.1 + url: https://conda.anaconda.org/conda-forge/linux-64/uv-0.3.3-h0f3a69f_0.conda + version: 0.3.3 - category: main dependencies: __osx: '>=10.13' libcxx: '>=17' hash: - md5: e4496784d3a61cefa821656c30883d91 - sha256: 65c9c7cffb8f99b77f9dd3ac63710009b17a10581ec4871e1214a3c862321921 + md5: 1263ac12932e6da5737a2553f8612c7b + sha256: 30cc5d4461c79a0fa95c20b588c036a4d5d36fbcd48f4e51b4a92a5d95397e21 manager: conda name: uv optional: false platform: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/uv-0.3.1-h032dd4e_0.conda - version: 0.3.1 + url: https://conda.anaconda.org/conda-forge/osx-64/uv-0.3.3-h032dd4e_0.conda + version: 0.3.3 - category: main dependencies: __osx: '>=11.0' libcxx: '>=17' hash: - md5: f0615e8d0565b62dd85be8caf63a5d95 - sha256: f2acfce3a0f133aa40aa2dc75dd7e3c3cc228794837804b9900ab83976e6c93c + md5: 1963d1c8b906f31ee80b157a51af9062 + sha256: b9453c7c6f19ebfcbc3663dbcbcb02ca91fe99f4604e22b755fb6922f7182c95 manager: conda name: uv optional: false platform: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.3.1-hd3a8144_0.conda - version: 0.3.1 + url: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.3.3-hd3a8144_0.conda + version: 0.3.3 + - category: main + dependencies: + click: '>=7.0' + h11: '>=0.8' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 12c28839ee30216dc237bd1e792c300b + sha256: 3b3d6ff5bc4eb447c621bc001b48c26560d37fe3619cc20cafb4a89ff022e8ad + manager: conda + name: uvicorn + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/uvicorn-0.30.6-py311h38be061_0.conda + version: 0.30.6 + - category: main + dependencies: + click: '>=7.0' + h11: '>=0.8' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: dea4fc6ce54194172ca7719ce8a08c42 + sha256: 7e8dc2250f0839643b22b5626f565f7035f979ff3b1e5cc8ed33c92dfd99e33d + manager: conda + name: uvicorn + optional: false + platform: osx-64 + url: + https://conda.anaconda.org/conda-forge/osx-64/uvicorn-0.30.6-py311h6eed73b_0.conda + version: 0.30.6 + - category: main + dependencies: + click: '>=7.0' + h11: '>=0.8' + python: '>=3.11,<3.12.0a0' + python_abi: 3.11.* + hash: + md5: 3b6dab51fc6abf3da6d36dd0f46ef99c + sha256: 430923848f14ca7c59c65296aca0d13a338b8fdbdee638532b9ea231a49686ec + manager: conda + name: uvicorn + optional: false + platform: osx-arm64 + url: + https://conda.anaconda.org/conda-forge/osx-arm64/uvicorn-0.30.6-py311h267d04e_0.conda + version: 0.30.6 - category: main dependencies: distlib: <1,>=0.3.7 @@ -13613,6 +14906,45 @@ package: url: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_2.conda version: 0.5.1 + - category: main + dependencies: + markupsafe: '>=2.1.1' + python: '>=3.8' + hash: + md5: 28753b434f2090f174d0c35ea629cc24 + sha256: 05cc8f76cb7b274ab1c78a1a8d421d1c084421e612829c33ce32af4e06039a92 + manager: conda + name: werkzeug + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/werkzeug-3.0.4-pyhd8ed1ab_0.conda + version: 3.0.4 + - category: main + dependencies: + markupsafe: '>=2.1.1' + python: '>=3.8' + hash: + md5: 28753b434f2090f174d0c35ea629cc24 + sha256: 05cc8f76cb7b274ab1c78a1a8d421d1c084421e612829c33ce32af4e06039a92 + manager: conda + name: werkzeug + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/werkzeug-3.0.4-pyhd8ed1ab_0.conda + version: 3.0.4 + - category: main + dependencies: + markupsafe: '>=2.1.1' + python: '>=3.8' + hash: + md5: 28753b434f2090f174d0c35ea629cc24 + sha256: 05cc8f76cb7b274ab1c78a1a8d421d1c084421e612829c33ce32af4e06039a92 + manager: conda + name: werkzeug + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/werkzeug-3.0.4-pyhd8ed1ab_0.conda + version: 3.0.4 - category: main dependencies: libgcc-ng: '>=12' @@ -13740,6 +15072,45 @@ package: url: https://conda.anaconda.org/conda-forge/osx-arm64/wrapt-1.16.0-py311h05b510d_0.conda version: 1.16.0 + - category: main + dependencies: + h11: '>=0.9.0,<1.0' + python: '>=3.7' + hash: + md5: 00ba804b54f451d102f6a7615f08470d + sha256: 66bd3f2db31fb62a2ff1f48d2c69ccdd2fa4467741149a0ad5c0bd097e0ac0e7 + manager: conda + name: wsproto + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2 + version: 1.2.0 + - category: main + dependencies: + h11: '>=0.9.0,<1.0' + python: '>=3.7' + hash: + md5: 00ba804b54f451d102f6a7615f08470d + sha256: 66bd3f2db31fb62a2ff1f48d2c69ccdd2fa4467741149a0ad5c0bd097e0ac0e7 + manager: conda + name: wsproto + optional: false + platform: osx-64 + url: https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2 + version: 1.2.0 + - category: main + dependencies: + h11: '>=0.9.0,<1.0' + python: '>=3.7' + hash: + md5: 00ba804b54f451d102f6a7615f08470d + sha256: 66bd3f2db31fb62a2ff1f48d2c69ccdd2fa4467741149a0ad5c0bd097e0ac0e7 + manager: conda + name: wsproto + optional: false + platform: osx-arm64 + url: https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2 + version: 1.2.0 - category: main dependencies: python: '>=3.5' @@ -13776,6 +15147,20 @@ package: platform: osx-arm64 url: https://conda.anaconda.org/conda-forge/noarch/wurlitzer-3.1.1-pyhd8ed1ab_0.conda version: 3.1.1 + - category: main + dependencies: + libgcc-ng: '>=12' + xorg-libx11: '>=1.8.9,<2.0a0' + xorg-libxmu: '>=1.1.3,<2.0a0' + hash: + md5: 43ece82367535e6ca703afeef42f897f + sha256: cd052414e84790a5d18fe6f4d7a6101642e1ea5312eb0f98bf7c1f071f23fabb + manager: conda + name: xclip + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/xclip-0.13-h4ab18f5_1.conda + version: '0.13' - category: main dependencies: libgcc-ng: '>=9.3.0' @@ -13875,6 +15260,22 @@ package: url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda version: 1.3.4 + - category: main + dependencies: + libgcc-ng: '>=12' + xorg-libx11: '>=1.8.9,<2.0a0' + xorg-libxext: '>=1.3.4,<2.0a0' + xorg-libxt: '>=1.3.0,<2.0a0' + hash: + md5: 4d6c9925cdcda27e9d022e40eb3eac05 + sha256: a34986d71949ba714b27080c8ebb4932857f6e2ebd6383fbb1639415b30f4fd0 + manager: conda + name: xorg-libxmu + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/xorg-libxmu-1.1.3-h4ab18f5_1.conda + version: 1.1.3 - category: main dependencies: libgcc-ng: '>=12' @@ -13890,6 +15291,24 @@ package: url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda version: 0.9.11 + - category: main + dependencies: + libgcc-ng: '>=12' + xorg-kbproto: '' + xorg-libice: '>=1.1.1,<2.0a0' + xorg-libsm: '>=1.2.4,<2.0a0' + xorg-libx11: '>=1.8.6,<2.0a0' + xorg-xproto: '' + hash: + md5: ae92aab42726eb29d16488924f7312cb + sha256: e7648d1efe2e858c4bc63ccf4a637c841dc971b37ded85a01be97a5e240fecfa + manager: conda + name: xorg-libxt + optional: false + platform: linux-64 + url: + https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.0-hd590300_1.conda + version: 1.3.0 - category: main dependencies: libgcc-ng: '>=9.3.0' @@ -13929,6 +15348,19 @@ package: url: https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2 version: 7.0.31 + - category: main + dependencies: + libgcc-ng: '>=12' + xorg-libx11: '>=1.8.9,<2.0a0' + hash: + md5: 396060c46e1839b3e9efee164f41f1ba + sha256: 1d889e7c94a7a20062dac2124944ca0d8ad10826bc5cab0e0c14205196471604 + manager: conda + name: xsel + optional: false + platform: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/xsel-1.2.1-h4ab18f5_2.conda + version: 1.2.1 - category: main dependencies: libgcc-ng: '>=12' @@ -14147,56 +15579,50 @@ package: version: 1.3.1 - category: main dependencies: - __glibc: '>=2.17,<3.0.a0' - cffi: '>=1.11' + cffi: '>=1.8' libgcc-ng: '>=12' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* - zstd: '>=1.5.6,<1.6.0a0' hash: - md5: 8efe4fe2396281627b3450af8357b190 - sha256: ee4e7202ed6d6027eabb9669252b4dfd8144d4fde644435ebe39ab608086e7af + md5: 056b3271f46abaa4673c8c6783283a07 + sha256: 8aac43cc4fbdcc420fe8a22c764b67f6ac9168b103bfd10d79a82b748304ddf6 manager: conda name: zstandard optional: false platform: linux-64 url: - https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py311h5cd10c7_0.conda - version: 0.23.0 + https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.19.0-py311hd4cff14_0.tar.bz2 + version: 0.19.0 - category: main dependencies: - __osx: '>=10.13' - cffi: '>=1.11' + cffi: '>=1.8' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* - zstd: '>=1.5.6,<1.6.0a0' hash: - md5: 9e5d830263cca953b20bb760ca4b6a0d - sha256: 5cbac17776b5c8bd27f08f6db4b05a7dc886966370626132654e1418a828931f + md5: 96e4e2aa960398abbe5c4a6cf22269b8 + sha256: b470229c05df4d96d27904def00660b5dfa7ad57bf2b9dfd826325233f9e8510 manager: conda name: zstandard optional: false platform: osx-64 url: - https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.23.0-py311h51fa951_0.conda - version: 0.23.0 + https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.19.0-py311h5547dcb_0.tar.bz2 + version: 0.19.0 - category: main dependencies: - __osx: '>=11.0' - cffi: '>=1.11' + cffi: '>=1.8' python: '>=3.11,<3.12.0a0' python_abi: 3.11.* - zstd: '>=1.5.6,<1.6.0a0' hash: - md5: 0571c2ddfd8f08fbf08f3333ac826b2d - sha256: c372898778c58816cf8ad0031504ffb9a451d92c8547e2e524e6e61c1df5d9a3 + md5: ece21cb47a93c985aa4b44219c4c8c8b + sha256: 43eaee70cd406468d96d1643b75d16e0da3955a9c1d37056767134b91b61d515 manager: conda name: zstandard optional: false platform: osx-arm64 url: - https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py311h4a6b76e_0.conda - version: 0.23.0 + https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.19.0-py311he2be06e_0.tar.bz2 + version: 0.19.0 - category: main dependencies: libgcc-ng: '>=12' diff --git a/conda_forge_tick/all_feedstocks.py b/conda_forge_tick/all_feedstocks.py index 1bde6e8cf..c7c167fca 100644 --- a/conda_forge_tick/all_feedstocks.py +++ b/conda_forge_tick/all_feedstocks.py @@ -1,4 +1,5 @@ import logging +import os from typing import List import tqdm @@ -9,11 +10,15 @@ logger = logging.getLogger(__name__) +DEFAULT_CONDA_FORGE_ORG = "conda-forge" +ENV_OVERRIDE_CONDA_FORGE_ORG = "CF_TICK_OVERRIDE_CONDA_FORGE_ORG" + def get_all_feedstocks_from_github(): gh = github_client() - org = gh.get_organization("conda-forge") + org_name = os.getenv(ENV_OVERRIDE_CONDA_FORGE_ORG, DEFAULT_CONDA_FORGE_ORG) + org = gh.get_organization(org_name) archived = set() not_archived = set() default_branches = {} diff --git a/conda_forge_tick/deploy.py b/conda_forge_tick/deploy.py index 059d7f941..a8d8fe4b1 100644 --- a/conda_forge_tick/deploy.py +++ b/conda_forge_tick/deploy.py @@ -6,6 +6,15 @@ from .lazy_json_backends import CF_TICK_GRAPH_DATA_HASHMAPS, get_lazy_json_backends from .utils import get_bot_run_url, load_existing_graph, run_command_hiding_token +""" +Environment Variables: + +GITHUB_WORKFLOW (optional): The name of the workflow. +RUN_URL (optional): The URL of the run. +BOT_TOKEN (optional): The bot's GitHub token. +DEPLOY_REPO (optional): The GitHub repository to deploy to. Default: "regro/cf-graph-countyfair". +""" + def _run_git_cmd(cmd, **kwargs): return subprocess.run(["git"] + cmd, check=True, **kwargs) @@ -67,7 +76,9 @@ def _deploy_batch(*, files_to_add, batch, n_added, max_per_batch=200): "push", "https://{token}@github.com/{deploy_repo}.git".format( token=env.get("BOT_TOKEN", ""), - deploy_repo="regro/cf-graph-countyfair", + deploy_repo=os.getenv( + "DEPLOY_REPO", "regro/cf-graph-countyfair" + ), ), "master", ], diff --git a/conda_forge_tick/feedstock_parser.py b/conda_forge_tick/feedstock_parser.py index a6f873949..17a00f91a 100644 --- a/conda_forge_tick/feedstock_parser.py +++ b/conda_forge_tick/feedstock_parser.py @@ -36,6 +36,8 @@ # to build graph edges BOOTSTRAP_MAPPINGS = {} +ENV_OVERRIDE_CONDA_FORGE_ORG = "CF_TICK_OVERRIDE_CONDA_FORGE_ORG" + def _dedupe_list_ordered(list_with_dupes): if not isinstance(list_with_dupes, list): @@ -166,11 +168,12 @@ def _extract_requirements(meta_yaml, outputs_to_keep=None): def _fetch_static_repo(name, dest): + conda_forge_org = os.getenv(ENV_OVERRIDE_CONDA_FORGE_ORG, "conda-forge") found_branch = None for branch in ["main", "master"]: try: r = requests.get( - f"https://github.com/conda-forge/{name}-feedstock/archive/{branch}.zip", + f"https://github.com/{conda_forge_org}/{name}-feedstock/archive/{branch}.zip", ) r.raise_for_status() found_branch = branch @@ -607,6 +610,7 @@ def load_feedstock_containerized( ], json_loads=loads, input=json_blob, + pass_env_vars=[ENV_OVERRIDE_CONDA_FORGE_ORG], ) return data diff --git a/conda_forge_tick/migration_runner.py b/conda_forge_tick/migration_runner.py index f4726d1c8..8fa413e50 100644 --- a/conda_forge_tick/migration_runner.py +++ b/conda_forge_tick/migration_runner.py @@ -158,13 +158,13 @@ def run_migration_containerized( data = run_container_task( "migrate-feedstock", args, - mount_readonly=False, - mount_dir=tmpdir, input=( dumps(node_attrs.data) if isinstance(node_attrs, LazyJson) else dumps(node_attrs) ), + mount_readonly=False, + mount_dir=tmpdir, ) sync_dirs( diff --git a/conda_forge_tick/provide_source_code.py b/conda_forge_tick/provide_source_code.py index 4c6cd8afd..39aa809bd 100644 --- a/conda_forge_tick/provide_source_code.py +++ b/conda_forge_tick/provide_source_code.py @@ -71,10 +71,7 @@ def provide_source_code_containerized(recipe_dir): tmp_source_dir = os.path.join(tmpdir, "source_dir") run_container_task( - "provide-source-code", - [], - mount_readonly=False, - mount_dir=tmpdir, + "provide-source-code", [], mount_readonly=False, mount_dir=tmpdir ) yield tmp_source_dir diff --git a/conda_forge_tick/rerender_feedstock.py b/conda_forge_tick/rerender_feedstock.py index ff8a55e34..e59cadc5e 100644 --- a/conda_forge_tick/rerender_feedstock.py +++ b/conda_forge_tick/rerender_feedstock.py @@ -100,10 +100,7 @@ def rerender_feedstock_containerized(feedstock_dir, timeout=900): ) data = run_container_task( - "rerender-feedstock", - args, - mount_readonly=False, - mount_dir=tmpdir, + "rerender-feedstock", args, mount_readonly=False, mount_dir=tmpdir ) if data["commit_message"] is not None: diff --git a/conda_forge_tick/solver_checks.py b/conda_forge_tick/solver_checks.py index 0f3962ac3..7b3f3f642 100644 --- a/conda_forge_tick/solver_checks.py +++ b/conda_forge_tick/solver_checks.py @@ -136,10 +136,7 @@ def _is_recipe_solvable_containerized( ) data = run_container_task( - "check-solvable", - args, - mount_readonly=True, - mount_dir=tmp_feedstock_dir, + "check-solvable", args, mount_readonly=True, mount_dir=tmp_feedstock_dir ) # When tempfile removes tempdir, it tries to reset permissions on subdirs. diff --git a/conda_forge_tick/update_upstream_versions.py b/conda_forge_tick/update_upstream_versions.py index 9ba6bf9f6..86d5b3afb 100644 --- a/conda_forge_tick/update_upstream_versions.py +++ b/conda_forge_tick/update_upstream_versions.py @@ -462,6 +462,10 @@ def extract_payload(node: Tuple[str, Mapping[str, Mapping]]) -> Tuple[str, Mappi payload_extracted = map(extract_payload, job_nodes) + # TODO: remove this + print("Job Nodes:", job_nodes) + print("Payload Extracted:", payload_extracted) + to_update: List[Tuple[str, Mapping]] = list( filter( lambda node: include_node(node[0], node[1]), diff --git a/conda_forge_tick/utils.py b/conda_forge_tick/utils.py index 8a39690b7..cecfdbb66 100644 --- a/conda_forge_tick/utils.py +++ b/conda_forge_tick/utils.py @@ -196,8 +196,9 @@ def run_container_task( json_loads: Callable = json.loads, tmpfs_size_mb: int = DEFAULT_CONTAINER_TMPFS_SIZE_MB, input: Optional[str] = None, - mount_dir: Optional[str] = None, + pass_env_vars: Optional[Iterable[str]] = None, mount_readonly: bool = True, + mount_dir: Optional[str] = None, ): """Run a bot task in a container. @@ -213,6 +214,11 @@ def run_container_task( The size of the tmpfs in MB, by default 10. input The input to pass to the container, by default None. + pass_env_vars + The environment variables to pass to the container, by default None. + You only pass the names of the environment variables. The values are + taken from the current environment. + If the environment variable is not set, it is not passed and no error is raised. mount_dir The directory to mount to the container at `/cf_tick_dir`, by default None. mount_readonly @@ -231,12 +237,20 @@ def run_container_task( else: mnt_args = [] + env_args = [] + for env_arg_name in pass_env_vars or []: + if env_arg_name not in os.environ: + logger.debug("environment variable %s not set, not passing", env_arg_name) + continue + env_args.extend(["-e", f"{env_arg_name}={os.environ[env_arg_name]}"]) + log_level_str = str(logging.getLevelName(logger.getEffectiveLevel())).lower() logger.debug("computed effective logging level: %s", log_level_str) cmd = [ *get_default_container_run_args(tmpfs_size_mb=tmpfs_size_mb), *mnt_args, + *env_args, get_default_container_name(), "/opt/conda/envs/cf-scripts/bin/python", "-u", @@ -485,10 +499,7 @@ def parse_recipe_yaml_containerized( args += ["--for-pinning"] return run_container_task( - "parse-recipe-yaml", - args, - input=text, - mount_readonly=True, + "parse-recipe-yaml", args, input=text, mount_readonly=True ) diff --git a/environment.yml b/environment.yml index 1ae2f357a..a3063df5d 100644 --- a/environment.yml +++ b/environment.yml @@ -23,6 +23,7 @@ dependencies: - curl - depfinder - distributed + - fastapi - feedparser - frozendict - git @@ -31,6 +32,7 @@ dependencies: - jinja2 - lockfile - mamba>=0.23 + - mitmproxy - msgpack-python - networkx!=2.8.1 - numpy diff --git a/tests/test_container_tasks.py b/tests/test_container_tasks.py index 17de11e86..1a825531b 100644 --- a/tests/test_container_tasks.py +++ b/tests/test_container_tasks.py @@ -82,8 +82,7 @@ ) def test_container_tasks_get_latest_version(use_containers): data = run_container_task( - "get-latest-version", - ["--existing-feedstock-node-attrs", "conda-smithy"], + "get-latest-version", ["--existing-feedstock-node-attrs", "conda-smithy"] ) assert VersionOrder(data["new_version"]) >= VersionOrder(conda_smithy.__version__) @@ -156,8 +155,7 @@ def test_container_tasks_get_latest_version_containerized_mpas_tools(use_contain def test_container_tasks_parse_feedstock(use_containers): with tempfile.TemporaryDirectory() as tmpdir, pushd(tmpdir): data = run_container_task( - "parse-feedstock", - ["--existing-feedstock-node-attrs", "conda-smithy"], + "parse-feedstock", ["--existing-feedstock-node-attrs", "conda-smithy"] ) with ( diff --git a/tests_integration/README.md b/tests_integration/README.md new file mode 100644 index 000000000..2da49cc33 --- /dev/null +++ b/tests_integration/README.md @@ -0,0 +1,35 @@ +# Integration Tests +This directory contains integration tests for the autotick-bot. +The tests are run against actual GitHub repositories, and are used to verify that the +bot works as expected in an environment closely resembling production. + +## Environment Variables +The tests require the following environment variables to be set: + +| Variable | Description | +|--------------------------------|------------------------------------------------------------------------------------------------| +| `GH_TOKEN_STAGING_CONDA_FORGE` | Personal Access Token (PAT) for the `conda-forge-bot-staging` GitHub organization (see below). | +| `GH_TOKEN_STAGING_BOT_USER` | PAT for `cf-regro-autotick-bot-staging` GitHub user (see below). | +| `GH_TOKEN_STAGING_REGRO` | PAT for the `regro-staging` GitHub organization (see below). | +| `GITHUB_OUTPUT` | Set by GitHub. Name of an output file for script outputs. | +| `GITHUB_RUN_ID` | Set by GitHub. ID of the current run. Used as random seed. | + + +### GitHub Token Permissions +All tokens should have the following permissions: + +**Repository Access:** All repositories. + +**Repository Permissions:** +- Actions: read and write +- Administration: read and write +- Contents: read and write +- Metadata: read-only +- Pull requests: read and write +- Workflows: read and write + +**Organization Permissions:** None. + +## Structure of the Test Case Definitions +Inside the `definitions` module, each feedstock that is part of the test suite has its own +submodule. diff --git a/tests_integration/__init__.py b/tests_integration/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests_integration/clear_runner.sh b/tests_integration/clear_runner.sh new file mode 100755 index 000000000..cc8149bdc --- /dev/null +++ b/tests_integration/clear_runner.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Run this script in between bot steps to clear the runner from local artifacts. + +set -euxo pipefail + +rm -rf cf-graph +rm -rf conda-forge-pinning-feedstock diff --git a/tests_integration/collect_test_scenarios.py b/tests_integration/collect_test_scenarios.py new file mode 100644 index 000000000..0bd1c7b3c --- /dev/null +++ b/tests_integration/collect_test_scenarios.py @@ -0,0 +1,93 @@ +import collections +import os +import random + +from tests_integration.shared import DEFINITIONS_DIR, ENV_GITHUB_RUN_ID + +SKIP_TEST_CASES = {"__init__"} + + +def collect_integration_test_cases() -> dict[str, list[str]]: + """ + For each feedstock, return a list of all test cases that should be run for it. + The test cases do not include the feedstock name or the .py extension. + + Example return value: + { + "feedstock1": ["aarch_migration", "version_update"], + "feedstock2": ["version_update"], + } + + The return value of this function is deterministic (sorted by feedstock name and test case name). + """ + test_cases = collections.defaultdict(list) + + for test_case in DEFINITIONS_DIR.glob("*/*.py"): + test_case_name = test_case.stem + if test_case_name in SKIP_TEST_CASES: + continue + feedstock = test_case.parent.name + test_cases[feedstock].append(test_case_name) + + return dict( + sorted( + (feedstock, sorted(test_cases)) + for feedstock, test_cases in test_cases.items() + ) + ) + + +def get_number_of_test_scenarios(integration_test_cases: dict[str, list[str]]) -> int: + return max(len(test_cases) for test_cases in integration_test_cases.values()) + + +def get_all_test_scenario_ids( + integration_test_cases: dict[str, list[str]], +) -> list[int]: + return list(range(get_number_of_test_scenarios(integration_test_cases))) + + +def init_random(): + random.seed(int(os.environ[ENV_GITHUB_RUN_ID])) + + +def get_test_scenario(scenario_id: int) -> dict[str, str]: + """ + Get the test scenario for the given ID. + The scenario is a dictionary with the feedstock name as key and the test case name as value. + + Test scenarios are pseudo-randomly generated with the GitHub run ID as seed. + """ + init_random() + integration_test_cases = collect_integration_test_cases() + + n_scenarios = get_number_of_test_scenarios(integration_test_cases) + + if n_scenarios < 0 or scenario_id >= n_scenarios: + raise ValueError( + f"Invalid scenario ID: {scenario_id}. Must be between 0 and {n_scenarios - 1}." + ) + + # make sure that each feedstock has exactly n_scenarios test cases + # We have to cut the additional test cases here to avoid that some test cases are not run. + test_cases_extended = { + feedstock: ( + test_cases + * (n_scenarios // len(test_cases) + (n_scenarios % len(test_cases) > 0)) + )[:n_scenarios] + for feedstock, test_cases in integration_test_cases.items() + } + + for test_cases in test_cases_extended.values(): + random.shuffle(test_cases) + + def pop_test_scenario(): + scenario: dict[str, str] = {} + for feedstock in test_cases_extended: + scenario[feedstock] = test_cases_extended[feedstock].pop() + return scenario + + for _ in range(scenario_id): + pop_test_scenario() + + return pop_test_scenario() diff --git a/tests_integration/definitions/__init__.py b/tests_integration/definitions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests_integration/definitions/llvmdev/__init__.py b/tests_integration/definitions/llvmdev/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests_integration/definitions/llvmdev/other_test.py b/tests_integration/definitions/llvmdev/other_test.py new file mode 100644 index 000000000..19ef3cf34 --- /dev/null +++ b/tests_integration/definitions/llvmdev/other_test.py @@ -0,0 +1,16 @@ +from fastapi import APIRouter + +from tests_integration.lib.integration_test_helper import IntegrationTestHelper + +router = APIRouter() + + +@router.get("/pypi.org/pypi/pydantic/json") +def handle(): + return { + "new_version": "1.8.2", + } + + +def prepare(helper: IntegrationTestHelper): + pass diff --git a/tests_integration/definitions/llvmdev/version_update.py b/tests_integration/definitions/llvmdev/version_update.py new file mode 100644 index 000000000..19ef3cf34 --- /dev/null +++ b/tests_integration/definitions/llvmdev/version_update.py @@ -0,0 +1,16 @@ +from fastapi import APIRouter + +from tests_integration.lib.integration_test_helper import IntegrationTestHelper + +router = APIRouter() + + +@router.get("/pypi.org/pypi/pydantic/json") +def handle(): + return { + "new_version": "1.8.2", + } + + +def prepare(helper: IntegrationTestHelper): + pass diff --git a/tests_integration/definitions/pydantic/__init__.py b/tests_integration/definitions/pydantic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests_integration/definitions/pydantic/resources/feedstock/LICENSE.txt b/tests_integration/definitions/pydantic/resources/feedstock/LICENSE.txt new file mode 100644 index 000000000..2ec51d75f --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/LICENSE.txt @@ -0,0 +1,27 @@ +BSD-3-Clause license +Copyright (c) 2015-2022, conda-forge contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/tests_integration/definitions/pydantic/resources/feedstock/README.md b/tests_integration/definitions/pydantic/resources/feedstock/README.md new file mode 100644 index 000000000..557a024bb --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/README.md @@ -0,0 +1,157 @@ +About pydantic-feedstock +======================== + +Feedstock license: [BSD-3-Clause](https://github.com/conda-forge/pydantic-feedstock/blob/main/LICENSE.txt) + +Home: https://github.com/pydantic/pydantic + +Package license: MIT + +Summary: Data validation and settings management using python type hinting + +Development: https://github.com/pydantic/pydantic + +Documentation: https://docs.pydantic.dev + +Data validation and settings management using python type hinting. +See documentation for more details. + + +Current build status +==================== + + + + + +
All platforms: + + + +
+ +Current release info +==================== + +| Name | Downloads | Version | Platforms | +| --- | --- | --- | --- | +| [![Conda Recipe](https://img.shields.io/badge/recipe-pydantic-green.svg)](https://anaconda.org/conda-forge/pydantic) | [![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) | [![Conda Version](https://img.shields.io/conda/vn/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) | [![Conda Platforms](https://img.shields.io/conda/pn/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) | + +Installing pydantic +=================== + +Installing `pydantic` from the `conda-forge` channel can be achieved by adding `conda-forge` to your channels with: + +``` +conda config --add channels conda-forge +conda config --set channel_priority strict +``` + +Once the `conda-forge` channel has been enabled, `pydantic` can be installed with `conda`: + +``` +conda install pydantic +``` + +or with `mamba`: + +``` +mamba install pydantic +``` + +It is possible to list all of the versions of `pydantic` available on your platform with `conda`: + +``` +conda search pydantic --channel conda-forge +``` + +or with `mamba`: + +``` +mamba search pydantic --channel conda-forge +``` + +Alternatively, `mamba repoquery` may provide more information: + +``` +# Search all versions available on your platform: +mamba repoquery search pydantic --channel conda-forge + +# List packages depending on `pydantic`: +mamba repoquery whoneeds pydantic --channel conda-forge + +# List dependencies of `pydantic`: +mamba repoquery depends pydantic --channel conda-forge +``` + + +About conda-forge +================= + +[![Powered by +NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](https://numfocus.org) + +conda-forge is a community-led conda channel of installable packages. +In order to provide high-quality builds, the process has been automated into the +conda-forge GitHub organization. The conda-forge organization contains one repository +for each of the installable packages. Such a repository is known as a *feedstock*. + +A feedstock is made up of a conda recipe (the instructions on what and how to build +the package) and the necessary configurations for automatic building using freely +available continuous integration services. Thanks to the awesome service provided by +[Azure](https://azure.microsoft.com/en-us/services/devops/), [GitHub](https://github.com/), +[CircleCI](https://circleci.com/), [AppVeyor](https://www.appveyor.com/), +[Drone](https://cloud.drone.io/welcome), and [TravisCI](https://travis-ci.com/) +it is possible to build and upload installable packages to the +[conda-forge](https://anaconda.org/conda-forge) [anaconda.org](https://anaconda.org/) +channel for Linux, Windows and OSX respectively. + +To manage the continuous integration and simplify feedstock maintenance +[conda-smithy](https://github.com/conda-forge/conda-smithy) has been developed. +Using the ``conda-forge.yml`` within this repository, it is possible to re-render all of +this feedstock's supporting files (e.g. the CI configuration files) with ``conda smithy rerender``. + +For more information please check the [conda-forge documentation](https://conda-forge.org/docs/). + +Terminology +=========== + +**feedstock** - the conda recipe (raw material), supporting scripts and CI configuration. + +**conda-smithy** - the tool which helps orchestrate the feedstock. + Its primary use is in the construction of the CI ``.yml`` files + and simplify the management of *many* feedstocks. + +**conda-forge** - the place where the feedstock and smithy live and work to + produce the finished article (built conda distributions) + + +Updating pydantic-feedstock +=========================== + +If you would like to improve the pydantic recipe or build a new +package version, please fork this repository and submit a PR. Upon submission, +your changes will be run on the appropriate platforms to give the reviewer an +opportunity to confirm that the changes result in a successful build. Once +merged, the recipe will be re-built and uploaded automatically to the +`conda-forge` channel, whereupon the built conda packages will be available for +everybody to install and use from the `conda-forge` channel. +Note that all branches in the conda-forge/pydantic-feedstock are +immediately built and any created packages are uploaded, so PRs should be based +on branches in forks and branches in the main repository should only be used to +build distinct package versions. + +In order to produce a uniquely identifiable distribution: + * If the version of a package **is not** being increased, please add or increase + the [``build/number``](https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#build-number-and-string). + * If the version of a package **is** being increased, please remember to return + the [``build/number``](https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#build-number-and-string) + back to 0. + +Feedstock Maintainers +===================== + +* [@davidbrochart](https://github.com/davidbrochart/) +* [@dgasmith](https://github.com/dgasmith/) +* [@pavelzw](https://github.com/pavelzw/) +* [@samuelcolvin](https://github.com/samuelcolvin/) diff --git a/tests_integration/definitions/pydantic/resources/feedstock/azure-pipelines.yml b/tests_integration/definitions/pydantic/resources/feedstock/azure-pipelines.yml new file mode 100644 index 000000000..8e1780e01 --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/azure-pipelines.yml @@ -0,0 +1,6 @@ +# This file was generated automatically from conda-smithy. To update this configuration, +# update the conda-forge.yml and/or the recipe/meta.yaml. +# -*- mode: yaml -*- + +jobs: + - template: ./.azure-pipelines/azure-pipelines-linux.yml diff --git a/tests_integration/definitions/pydantic/resources/feedstock/build-locally.py b/tests_integration/definitions/pydantic/resources/feedstock/build-locally.py new file mode 100755 index 000000000..f278dda3e --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/build-locally.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# +# This file has been generated by conda-smithy in order to build the recipe +# locally. +# +import glob +import os +import platform +import subprocess +from argparse import ArgumentParser + + +def setup_environment(ns): + os.environ["CONFIG"] = ns.config + os.environ["UPLOAD_PACKAGES"] = "False" + os.environ["IS_PR_BUILD"] = "True" + if ns.debug: + os.environ["BUILD_WITH_CONDA_DEBUG"] = "1" + if ns.output_id: + os.environ["BUILD_OUTPUT_ID"] = ns.output_id + if "MINIFORGE_HOME" not in os.environ: + os.environ["MINIFORGE_HOME"] = os.path.join( + os.path.dirname(__file__), "miniforge3" + ) + + +def run_docker_build(ns): + script = ".scripts/run_docker_build.sh" + subprocess.check_call([script]) + + +def run_osx_build(ns): + script = ".scripts/run_osx_build.sh" + subprocess.check_call([script]) + + +def verify_config(ns): + valid_configs = {os.path.basename(f)[:-5] for f in glob.glob(".ci_support/*.yaml")} + print(f"valid configs are {valid_configs}") + if ns.config in valid_configs: + print("Using " + ns.config + " configuration") + return + elif len(valid_configs) == 1: + ns.config = valid_configs.pop() + print("Found " + ns.config + " configuration") + elif ns.config is None: + print("config not selected, please choose from the following:\n") + selections = list(enumerate(sorted(valid_configs), 1)) + for i, c in selections: + print(f"{i}. {c}") + s = input("\n> ") + idx = int(s) - 1 + ns.config = selections[idx][1] + print(f"selected {ns.config}") + else: + raise ValueError("config " + ns.config + " is not valid") + # Remove the following, as implemented + if ns.config.startswith("win"): + raise ValueError( + f"only Linux/macOS configs currently supported, got {ns.config}" + ) + elif ns.config.startswith("osx"): + if "OSX_SDK_DIR" not in os.environ: + raise RuntimeError( + "Need OSX_SDK_DIR env variable set. Run 'export OSX_SDK_DIR=$PWD/SDKs' " + "to download the SDK automatically to '$PWD/SDKs/MacOSX.sdk'. " + "Note: OSX_SDK_DIR must be set to an absolute path. " + "Setting this variable implies agreement to the licensing terms of the SDK by Apple." + ) + + +def main(args=None): + p = ArgumentParser("build-locally") + p.add_argument("config", default=None, nargs="?") + p.add_argument( + "--debug", + action="store_true", + help="Setup debug environment using `conda debug`", + ) + p.add_argument("--output-id", help="If running debug, specify the output to setup.") + + ns = p.parse_args(args=args) + verify_config(ns) + setup_environment(ns) + + try: + if ns.config.startswith("linux") or ( + ns.config.startswith("osx") and platform.system() == "Linux" + ): + run_docker_build(ns) + elif ns.config.startswith("osx"): + run_osx_build(ns) + finally: + recipe_license_file = os.path.join("recipe", "recipe-scripts-license.txt") + if os.path.exists(recipe_license_file): + os.remove(recipe_license_file) + + +if __name__ == "__main__": + main() diff --git a/tests_integration/definitions/pydantic/resources/feedstock/conda-forge.yml b/tests_integration/definitions/pydantic/resources/feedstock/conda-forge.yml new file mode 100644 index 000000000..4c2f53718 --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/conda-forge.yml @@ -0,0 +1,19 @@ +build_platform: + linux_aarch64: linux_64 + linux_ppc64le: linux_64 + osx_arm64: osx_64 +conda_forge_output_validation: true +github: + branch_name: main + tooling_branch_name: main +provider: + linux_aarch64: default + linux_ppc64le: default + win: azure +conda_build: + pkg_format: '2' +bot: + inspection: update-grayskull + abi_migration_branches: + - 1.x +test: native_and_emulated diff --git a/tests_integration/definitions/pydantic/resources/feedstock/recipe/meta.yaml b/tests_integration/definitions/pydantic/resources/feedstock/recipe/meta.yaml new file mode 100644 index 000000000..99f8481bd --- /dev/null +++ b/tests_integration/definitions/pydantic/resources/feedstock/recipe/meta.yaml @@ -0,0 +1,56 @@ +{% set name = "pydantic" %} +{% set version = "2.8.2" %} +{% set repo_url = "https://github.com/pydantic/pydantic" %} +{% set docs_url = "https://docs.pydantic.dev" %} + +package: + name: {{ name }} + version: {{ version }} + +source: + url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz + sha256: 6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a + +build: + noarch: python + script: {{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv + number: 0 + +requirements: + host: + - python >=3.7 + - hatchling + - hatch-fancy-pypi-readme >=22.5.0 + - pip + run: + - python >=3.7 + - typing-extensions >=4.6.1 + - annotated-types >=0.4.0 + - pydantic-core ==2.20.1 + +test: + imports: + - pydantic + commands: + - pip check + requires: + - pip + +about: + home: {{ repo_url }} + license: MIT + license_family: MIT + license_file: LICENSE + summary: Data validation and settings management using python type hinting + description: | + Data validation and settings management using python type hinting. + See documentation <{{ docs_url }}> for more details. + doc_url: {{ docs_url }} + dev_url: {{ repo_url }} + +extra: + recipe-maintainers: + - samuelcolvin + - dgasmith + - davidbrochart + - pavelzw diff --git a/tests_integration/definitions/pydantic/version_update.py b/tests_integration/definitions/pydantic/version_update.py new file mode 100644 index 000000000..f5338fb17 --- /dev/null +++ b/tests_integration/definitions/pydantic/version_update.py @@ -0,0 +1,12 @@ +from pathlib import Path + +from fastapi import APIRouter + +from tests_integration.lib.integration_test_helper import IntegrationTestHelper + +router = APIRouter() + + +def prepare(helper: IntegrationTestHelper): + feedstock_dir = Path(__file__).parent / "resources" / "feedstock" + helper.overwrite_feedstock_contents("pydantic", feedstock_dir) diff --git a/tests_integration/lib/__init__.py b/tests_integration/lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests_integration/lib/integration_test_helper.py b/tests_integration/lib/integration_test_helper.py new file mode 100644 index 000000000..6b9b9565c --- /dev/null +++ b/tests_integration/lib/integration_test_helper.py @@ -0,0 +1,75 @@ +import logging +import shutil +import subprocess +from pathlib import Path +from tempfile import TemporaryDirectory + +from conda_forge_tick.utils import ( + print_subprocess_output_strip_token, +) +from tests_integration.shared import FEEDSTOCK_SUFFIX, GitHubAccount, get_github_token + +LOGGER = logging.getLogger(__name__) + + +class IntegrationTestHelper: + @classmethod + def overwrite_feedstock_contents(cls, feedstock_name: str, source_dir: Path): + """ + Overwrite the contents of the feedstock with the contents of the source directory. + This prunes the entire git history. + + :param feedstock_name: The name of the feedstock repository, without the "-feedstock" suffix. + :param source_dir: The directory containing the new contents of the feedstock. + """ + # We execute all git operations in a separate temporary directory to avoid side effects. + with TemporaryDirectory(feedstock_name) as tmpdir_str: + tmpdir = Path(tmpdir_str) + cls._overwrite_feedstock_contents_with_tmpdir( + feedstock_name, source_dir, tmpdir + ) + + @staticmethod + def _overwrite_feedstock_contents_with_tmpdir( + feedstock_name: str, source_dir: Path, tmpdir: Path + ): + """ + See `overwrite_feedstock_contents`. + """ + tmp_feedstock_dir = tmpdir / f"{feedstock_name}{FEEDSTOCK_SUFFIX}" + shutil.copytree(source_dir, tmp_feedstock_dir) + + # Remove the .git directory (if it exists) + shutil.rmtree(tmp_feedstock_dir / ".git", ignore_errors=True) + + # Initialize a new git repository and commit everything + subprocess.run(["git", "init"], cwd=tmp_feedstock_dir, check=True) + subprocess.run(["git", "add", "--all"], cwd=tmp_feedstock_dir, check=True) + subprocess.run( + ["git", "commit", "-m", "Overwrite Feedstock Contents"], + cwd=tmp_feedstock_dir, + check=True, + ) + + # Push the new contents to the feedstock repository + push_token = get_github_token(GitHubAccount.CONDA_FORGE_ORG) + push_res = subprocess.run( + [ + "git", + "push", + f"https://{push_token}@github.com/{GitHubAccount.CONDA_FORGE_ORG}/{feedstock_name}{FEEDSTOCK_SUFFIX}.git", + "main", + "--force", + ], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=tmp_feedstock_dir, + check=True, + ) + + print_subprocess_output_strip_token(push_res, token=push_token) + + LOGGER.info( + f"Feedstock contents of {feedstock_name} have been overwritten successfully." + ) diff --git a/tests_integration/mock_proxy_start.sh b/tests_integration/mock_proxy_start.sh new file mode 100755 index 000000000..6bab4944e --- /dev/null +++ b/tests_integration/mock_proxy_start.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +# You might need to set PYTHONPATH to the root of cf-scripts +mitmdump -s ./tests_integration/mock_server_addon.py --set connection_strategy=lazy --set upstream_cert=false diff --git a/tests_integration/mock_server_addon.py b/tests_integration/mock_server_addon.py new file mode 100644 index 000000000..0fa0b520b --- /dev/null +++ b/tests_integration/mock_server_addon.py @@ -0,0 +1,54 @@ +""" +Start this file with `mitmdump -s mock_server_addon.py`. + +This file expects an environment variable to be set to the ID of the test scenario to run. +The name of this variable is defined in `ENV_TEST_SCENARIO_ID`. + +Starting mitmdump from a Python script is not officially supported. +""" + +import logging +import os + +from fastapi import FastAPI +from mitmproxy.addons import asgiapp +from mitmproxy.http import HTTPFlow + +from tests_integration.collect_test_scenarios import get_test_scenario +from tests_integration.shared import ( + ENV_TEST_SCENARIO_ID, + get_test_case_modules, +) + +LOGGER = logging.getLogger(__name__) + +VIRTUAL_PROXY_HOSTNAME = "virtual.proxy" +VIRTUAL_PROXY_PORT = 80 + + +def request(flow: HTTPFlow): + flow.request.path = f"/{flow.request.host}{flow.request.path}" + flow.request.host = VIRTUAL_PROXY_HOSTNAME + flow.request.port = VIRTUAL_PROXY_PORT + flow.request.scheme = "http" + + +def _setup_fastapi(): + scenario_id = int(os.environ[ENV_TEST_SCENARIO_ID]) + scenario = get_test_scenario(scenario_id) + + app = FastAPI() + + for test_module in get_test_case_modules(scenario): + try: + LOGGER.info("Setting up mocks for %s...", test_module.__name__) + app.include_router(test_module.router) + except AttributeError: + raise AttributeError("The test case must define a FastAPI router.") + + return app + + +addons = [ + asgiapp.ASGIApp(_setup_fastapi(), VIRTUAL_PROXY_HOSTNAME, VIRTUAL_PROXY_PORT), +] diff --git a/tests_integration/setup_repositories.py b/tests_integration/setup_repositories.py new file mode 100644 index 000000000..786d1e52d --- /dev/null +++ b/tests_integration/setup_repositories.py @@ -0,0 +1,222 @@ +""" +This module is used by the integration tests to set up the GitHub repositories +that are needed for running the tests. + +We do not *create* any repositories within the bot's user account here. This is handled in the prepare function of the +test cases themselves because tests could purposefully rely on the actual bot itself to create repositories. + +However, we do delete unnecessary feedstocks from the bot's user account. + +After the repositories are set up, we write a list of all test scenario ids to be run to $GITHUB_OUTPUT. +""" + +import logging +from collections.abc import Iterable +from dataclasses import dataclass +from typing import Protocol + +from github import Github +from github.Repository import Repository + +from tests_integration.collect_test_scenarios import ( + collect_integration_test_cases, + get_all_test_scenario_ids, +) +from tests_integration.shared import ( + DEFINITIONS_DIR, + FEEDSTOCK_SUFFIX, + GITHUB_OUTPUT_KEY_SCENARIO_IDS, + REGRO_ACCOUNT_REPOS, + GitHubAccount, + get_github_token, + is_user_account, + setup_logging, + write_github_output, +) + +LOGGER = logging.getLogger(__name__) + +IGNORE_FEEDSTOCK_NAMES = { + "__pycache__", +} + + +@dataclass(frozen=True) +class GitHubAccountSetup: + """ + Information about the setup of a GitHub account for the integration tests. + """ + + account: GitHubAccount + """ + The GitHub account for which the setup is done. + """ + + target_names: set[str] + """ + The names of the repositories that should exist after the preparation (excluding the suffix). + """ + + suffix: str | None = None + """ + If given, only repositories with the given suffix are considered for deletion and the target names + are extended with the suffix. + """ + + delete_only: bool = False + """ + If True, only delete unnecessary repositories and do not create any new ones. + """ + + +class RepositoryOwner(Protocol): + def create_repo(self, name: str) -> Repository: + pass + + def get_repo(self, name: str) -> Repository: + pass + + def get_repos(self) -> Iterable[Repository]: + pass + + +def get_test_feedstock_names() -> set[str]: + """ + Returns the list of feedstock names that are needed for the integration tests. + The names do not include the "-feedstock" suffix. + """ + # note: the trailing "/" is needed to only get the directories, + # because of a Python bug this only works in Python 3.11 or later (which is fine) + # https://bugs.python.org/issue22276 + return {path.name for path in DEFINITIONS_DIR.glob("*/")} - IGNORE_FEEDSTOCK_NAMES + + +def _or_empty_set(value: set[str]) -> set[str] | str: + """ + Logging helper function that returns "{}" if the given set is empty. + """ + return value or "{}" + + +def prepare_repositories( + owner: RepositoryOwner, + owner_name: str, + existing_repos: Iterable[Repository], + target_names: Iterable[str], + delete_only: bool, + suffix: str | None = None, +): + """ + Prepares the repositories of a certain owner for the integration tests. + Unnecessary repositories are deleted and missing repositories are created. + + :param owner: The owner of the repositories. + :param owner_name: The name of the owner (for logging). + :param existing_repos: The existing repositories of the owner. + :param target_names: The names of the repositories that should exist after the preparation (excluding the suffix). + :param suffix: If given, only repositories with the given suffix are considered for deletion and the target names + are extended with the suffix. + :param delete_only: If True, only delete unnecessary repositories and do not create any new ones. + """ + existing_names = {repo.name for repo in existing_repos} + target_names = set(target_names) + + if suffix: + existing_names = {name for name in existing_names if name.endswith(suffix)} + target_names = {name + suffix for name in target_names} + + to_delete = existing_names - target_names + to_create = target_names - existing_names + + LOGGER.info( + "Deleting the following repositories for %s: %s", + owner_name, + _or_empty_set(to_delete), + ) + for name in to_delete: + owner.get_repo(name).delete() + + if delete_only: + return + + LOGGER.info( + "Creating the following repositories for %s: %s", + owner_name, + _or_empty_set(to_create), + ) + for name in to_create: + owner.create_repo(name) + + +def prepare_accounts(setup_infos: Iterable[GitHubAccountSetup]): + """ + Prepares the repositories of all GitHub accounts for the integration tests. + """ + for setup_info in setup_infos: + # for each account, we need to create a separate GitHub instance because different tokens are needed + github = Github(get_github_token(setup_info.account)) + + owner: RepositoryOwner + existing_repos: Iterable[Repository] + if is_user_account(setup_info.account): + current_user = github.get_user() + if current_user.login != setup_info.account: + raise ValueError("The token is not for the expected user") + owner = current_user + existing_repos = current_user.get_repos(type="owner") + else: + owner = github.get_organization(setup_info.account) + existing_repos = owner.get_repos() + + prepare_repositories( + owner=owner, + owner_name=setup_info.account, + existing_repos=existing_repos, + target_names=setup_info.target_names, + delete_only=setup_info.delete_only, + suffix=setup_info.suffix, + ) + + +def prepare_all_accounts(): + test_feedstock_names = get_test_feedstock_names() + logging.info("Test feedstock names: %s", _or_empty_set(test_feedstock_names)) + + setup_infos: list[GitHubAccountSetup] = [ + GitHubAccountSetup( + GitHubAccount.CONDA_FORGE_ORG, + test_feedstock_names | {"conda-forge-pinning"}, + FEEDSTOCK_SUFFIX, + ), + GitHubAccountSetup( + GitHubAccount.BOT_USER, + test_feedstock_names, + FEEDSTOCK_SUFFIX, + delete_only=True, # see the top-level comment for the reason + ), + GitHubAccountSetup( + GitHubAccount.REGRO_ORG, + REGRO_ACCOUNT_REPOS, + ), + ] + + prepare_accounts(setup_infos) + + +def _format_scenario_ids(scenario_ids: list[int]) -> str: + return "[" + ", ".join(str(s_id) for s_id in scenario_ids) + "]" + + +def write_scenario_ids(): + ids = get_all_test_scenario_ids(collect_integration_test_cases()) + write_github_output(GITHUB_OUTPUT_KEY_SCENARIO_IDS, _format_scenario_ids(ids)) + + +def main(): + prepare_all_accounts() + write_scenario_ids() + + +if __name__ == "__main__": + setup_logging(logging.INFO) + main() diff --git a/tests_integration/shared.py b/tests_integration/shared.py new file mode 100644 index 000000000..d6f4ac27b --- /dev/null +++ b/tests_integration/shared.py @@ -0,0 +1,75 @@ +import importlib +import logging +import os +import types +from collections.abc import Iterator +from enum import StrEnum +from pathlib import Path + + +class GitHubAccount(StrEnum): + CONDA_FORGE_ORG = "conda-forge-bot-staging" + BOT_USER = "regro-cf-autotick-bot-staging" + REGRO_ORG = "regro-staging" + + +GITHUB_TOKEN_ENV_VARS: dict[GitHubAccount, str] = { + GitHubAccount.CONDA_FORGE_ORG: "GH_TOKEN_STAGING_CONDA_FORGE", + GitHubAccount.BOT_USER: "GH_TOKEN_STAGING_BOT_USER", + GitHubAccount.REGRO_ORG: "GH_TOKEN_STAGING_REGRO", +} + +IS_USER_ACCOUNT: dict[GitHubAccount, bool] = { + GitHubAccount.CONDA_FORGE_ORG: False, + GitHubAccount.BOT_USER: True, + GitHubAccount.REGRO_ORG: False, +} + +REGRO_ACCOUNT_REPOS = { + "cf-graph-countyfair", +} + +ENV_GITHUB_OUTPUT = "GITHUB_OUTPUT" +ENV_GITHUB_RUN_ID = "GITHUB_RUN_ID" +""" +Used as a random seed for the integration tests. +""" +ENV_TEST_SCENARIO_ID = "SCENARIO_ID" + +GITHUB_OUTPUT_KEY_SCENARIO_IDS = "scenario_ids" + +TESTS_INTEGRATION_DIR_NAME = "tests_integration" +DEFINITIONS_DIR_NAME = "definitions" + +DEFINITIONS_DIR = Path(__file__).parent / DEFINITIONS_DIR_NAME + +FEEDSTOCK_SUFFIX = "-feedstock" + + +def setup_logging(level: int | str): + logging.basicConfig(level=level) + + +def get_github_token(account: GitHubAccount) -> str: + return os.environ[GITHUB_TOKEN_ENV_VARS[account]] + + +def is_user_account(account: GitHubAccount) -> bool: + return IS_USER_ACCOUNT[account] + + +def write_github_output(key: str, value: str): + with open(os.environ[ENV_GITHUB_OUTPUT], "a") as f: + f.write(f"{key}={value}\n") + + +def get_test_case_modules(scenario: dict[str, str]) -> Iterator[types.ModuleType]: + """ + Yields all test case modules of the given scenario. + """ + return ( + importlib.import_module( + f"{TESTS_INTEGRATION_DIR_NAME}.{DEFINITIONS_DIR_NAME}.{feedstock}.{test_case}" + ) + for feedstock, test_case in scenario.items() + ) diff --git a/tests_integration/step_prepare.py b/tests_integration/step_prepare.py new file mode 100644 index 000000000..1b35055f9 --- /dev/null +++ b/tests_integration/step_prepare.py @@ -0,0 +1,63 @@ +""" +After closing all open Pull Requests in the conda-forge staging organization, +runs the prepare() method of all test cases of the current test scenario to prepare the test environment. + +Expects the scenario ID to be present in the environment variable named after ENV_TEST_SCENARIO_ID. +""" + +import logging +import os + +from github import Github + +from tests_integration.collect_test_scenarios import get_test_scenario +from tests_integration.lib.integration_test_helper import IntegrationTestHelper +from tests_integration.shared import ( + ENV_TEST_SCENARIO_ID, + FEEDSTOCK_SUFFIX, + GitHubAccount, + get_github_token, + get_test_case_modules, + setup_logging, +) + +LOGGER = logging.getLogger(__name__) + + +def close_all_open_pull_requests(): + github = Github(get_github_token(GitHubAccount.CONDA_FORGE_ORG)) + org = github.get_organization(GitHubAccount.CONDA_FORGE_ORG) + + for repo in org.get_repos(): + if not repo.name.endswith(FEEDSTOCK_SUFFIX): + continue + for pr in repo.get_pulls(state="open"): + pr.create_issue_comment( + "Closing this PR because it is a leftover from a previous test run." + ) + pr.edit(state="closed") + + +def run_all_prepare_functions(scenario: dict[str, str]): + test_helper = IntegrationTestHelper() + for test_module in get_test_case_modules(scenario): + try: + logging.info("Preparing %s...", test_module.__name__) + test_module.prepare(test_helper) + except AttributeError: + raise AttributeError("The test case must define a prepare() function.") + + +def main(scenario_id: int): + close_all_open_pull_requests() + scenario = get_test_scenario(scenario_id) + + logging.info("Preparing test scenario %d...", scenario_id) + logging.info("Scenario: %s", scenario) + + run_all_prepare_functions(scenario) + + +if __name__ == "__main__": + setup_logging(logging.INFO) + main(int(os.environ[ENV_TEST_SCENARIO_ID]))