From f1d37c757f8cc737b47102c229445bb6870bcbfd Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Sat, 27 Aug 2022 12:21:30 -0700 Subject: [PATCH 1/6] BLD: Build wheels using cibuildwheel --- .github/workflows/wheels.yml | 178 +++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 2 + ci/fix_wheels.py | 55 +++++++++++ ci/test_wheels.py | 58 ++++++++++++ ci/test_wheels_windows.bat | 9 ++ ci/upload_wheels.sh | 42 +++++++++ 6 files changed, 344 insertions(+) create mode 100644 .github/workflows/wheels.yml create mode 100644 ci/fix_wheels.py create mode 100644 ci/test_wheels.py create mode 100644 ci/test_wheels_windows.bat create mode 100644 ci/upload_wheels.sh diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml new file mode 100644 index 0000000000000..64f1f84da9547 --- /dev/null +++ b/.github/workflows/wheels.yml @@ -0,0 +1,178 @@ +# Workflow to build wheels for upload to PyPI. +# Inspired by numpy's cibuildwheel config https://github.com/numpy/numpy/blob/main/.github/workflows/wheels.yml +# +# In an attempt to save CI resources, wheel builds do +# not run on each push but only weekly and for releases. +# Wheel builds can be triggered from the Actions page +# (if you have the perms) on a commit to master. +# +# Alternatively, you can add labels to the pull request in order to trigger wheel +# builds. +# The label(s) that trigger builds are: +# - Build +name: Wheel builder + +on: + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + - cron: "42 1 * * 4" + push: + pull_request: + types: [labeled, opened, synchronize, reopened] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + build_wheels: + name: Build wheel for ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }} + if: >- + github.event_name == 'schedule' || + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'Build')) || + (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && ( ! endsWith(github.ref, 'dev0'))) + runs-on: ${{ matrix.buildplat[0] }} + strategy: + # Ensure that a wheel builder finishes even if another fails + fail-fast: false + matrix: + # Github Actions doesn't support pairing matrix values together, let's improvise + # https://github.com/github/feedback/discussions/7835#discussioncomment-1769026 + buildplat: + - [ubuntu-20.04, manylinux_x86_64] + - [macos-11, macosx_*] + - [windows-2019, win_amd64] + - [windows-2019, win32] + # TODO: support PyPy? + python: [["cp38", "3.8"], ["cp39", "3.9"], ["cp310", "3.10"]]# "pp38", "pp39"] + env: + IS_32_BIT: ${{ matrix.buildplat[1] == 'win32' }} + IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} + IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + steps: + - name: Checkout pandas + uses: actions/checkout@v3 + with: + submodules: true + # versioneer.py requires the latest tag to be reachable. Here we + # fetch the complete history to get access to the tags. + # A shallow clone can work when the following issue is resolved: + # https://github.com/actions/checkout/issues/338 + fetch-depth: 0 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.9.0 + env: + CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }} + CIBW_ENVIRONMENT: RUNNER_OS='${{ runner.os }}' + IS_32_BIT='${{ env.IS_32_BIT }}' + # We can't test directly with cibuildwheel, since we need to have to wheel location + # to mount into the docker image + CIBW_TEST_COMMAND_LINUX: "python {project}/ci/test_wheels.py" + CIBW_TEST_COMMAND_MACOS: "python {project}/ci/test_wheels.py" + CIBW_TEST_REQUIRES: hypothesis==6.52.1 pytest>=6.2.5 pytest-xdist pytest-asyncio>=0.17 + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "python ci/fix_wheels.py {wheel} {dest_dir}" + CIBW_ARCHS_MACOS: x86_64 universal2 + + # Used to push the built wheels + - uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python[1] }} + + - name: Test wheels (Windows 64-bit only) + if: ${{ matrix.buildplat[1] == 'win_amd64' }} + shell: cmd + run: | + python ci/test_wheels.py wheelhouse + + - uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.python[0] }}-${{ startsWith(matrix.buildplat[1], 'macosx') && 'macosx' || matrix.buildplat[1] }} + path: ./wheelhouse/*.whl + + - name: Upload wheels + if: success() + shell: bash + env: + PANDAS_STAGING_UPLOAD_TOKEN: ${{ secrets.PANDAS_STAGING_UPLOAD_TOKEN }} + PANDAS_NIGHTLY_UPLOAD_TOKEN: ${{ secrets.PANDAS_NIGHTLY_UPLOAD_TOKEN }} + run: | + source ci/upload_wheels.sh + set_upload_vars + # trigger an upload to + # https://anaconda.org/scipy-wheels-nightly/pandas + # for cron jobs or "Run workflow" (restricted to main branch). + # Tags will upload to + # https://anaconda.org/multibuild-wheels-staging/pandas + # The tokens were originally generated at anaconda.org + upload_wheels + build_sdist: + name: Build sdist + if: >- + github.event_name == 'schedule' || + github.event_name == 'workflow_dispatch' || + (github.event_name == 'pull_request' && + contains(github.event.pull_request.labels.*.name, 'Build')) || + (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && ( ! endsWith(github.ref, 'dev0'))) + runs-on: ubuntu-latest + env: + IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} + IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + steps: + - name: Checkout pandas + uses: actions/checkout@v3 + with: + submodules: true + # versioneer.py requires the latest tag to be reachable. Here we + # fetch the complete history to get access to the tags. + # A shallow clone can work when the following issue is resolved: + # https://github.com/actions/checkout/issues/338 + fetch-depth: 0 + # Used to push the built wheels + - uses: actions/setup-python@v3 + with: + # Build sdist on lowest supported Python + python-version: '3.8' + - name: Build sdist + run: | + pip install build + python -m build --sdist + - name: Test the sdist + run: | + # TODO: Don't run test suite, and instead build wheels from sdist + # Depends on pypa/cibuildwheel#1020 + python -m pip install dist/*.gz + pip install hypothesis==6.52.1 pytest>=6.2.5 pytest-xdist pytest-asyncio>=0.17 + cd .. # Not a good idea to test within the src tree + python -c "import pandas; print(pandas.__version__); + pandas.test(extra_args=['-m not clipboard and not single_cpu', '--skip-slow', '--skip-network', '--skip-db', '-n=2']); + pandas.test(extra_args=['-m not clipboard and single_cpu', '--skip-slow', '--skip-network', '--skip-db'])" + - uses: actions/upload-artifact@v3 + with: + name: sdist + path: ./dist/* + + - name: Upload sdist + if: success() + shell: bash + env: + PANDAS_STAGING_UPLOAD_TOKEN: ${{ secrets.PANDAS_STAGING_UPLOAD_TOKEN }} + PANDAS_NIGHTLY_UPLOAD_TOKEN: ${{ secrets.PANDAS_NIGHTLY_UPLOAD_TOKEN }} + run: | + source ci/upload_wheels.sh + set_upload_vars + # trigger an upload to + # https://anaconda.org/scipy-wheels-nightly/pandas + # for cron jobs or "Run workflow" (restricted to main branch). + # Tags will upload to + # https://anaconda.org/multibuild-wheels-staging/pandas + # The tokens were originally generated at anaconda.org + upload_wheels diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2ca5b5c9b896b..6e8f04ed54cc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,6 +49,8 @@ repos: rev: 5.0.4 hooks: - id: flake8 + # Need to patch os.remove rule in pandas-dev-flaker + exclude: ^ci/fix_wheels.py additional_dependencies: &flake8_dependencies - flake8==5.0.4 - flake8-bugbear==22.7.1 diff --git a/ci/fix_wheels.py b/ci/fix_wheels.py new file mode 100644 index 0000000000000..bb61a5674bbbb --- /dev/null +++ b/ci/fix_wheels.py @@ -0,0 +1,55 @@ +import os +import shutil +import struct +import sys +import zipfile + +try: + _, wheel_path, dest_dir = sys.argv + # Figure out whether we are building on 32 or 64 bit python + is_32 = struct.calcsize("P") * 8 == 32 + PYTHON_ARCH = "x86" if is_32 else "x64" +except ValueError: + # Too many/little values to unpack + raise ValueError( + "User must pass the path to the wheel and the destination directory." + ) +# Wheels are zip files +if not os.path.isdir(dest_dir): + print(f"Created directory {dest_dir}") + os.mkdir(dest_dir) +shutil.copy(wheel_path, dest_dir) # Remember to delete if process fails +wheel_name = os.path.basename(wheel_path) +success = True +exception = None +repaired_wheel_path = os.path.join(dest_dir, wheel_name) +with zipfile.ZipFile(repaired_wheel_path, "a") as zipf: + try: + # TODO: figure out how licensing works for the redistributables + base_redist_dir = ( + f"C:/Program Files (x86)/Microsoft Visual Studio/2019/" + f"Enterprise/VC/Redist/MSVC/14.29.30133/{PYTHON_ARCH}/" + f"Microsoft.VC142.CRT/" + ) + zipf.write( + os.path.join(base_redist_dir, "msvcp140.dll"), + "pandas/_libs/window/msvcp140.dll", + ) + zipf.write( + os.path.join(base_redist_dir, "concrt140.dll"), + "pandas/_libs/window/concrt140.dll", + ) + if not is_32: + zipf.write( + os.path.join(base_redist_dir, "vcruntime140_1.dll"), + "pandas/_libs/window/vcruntime140_1.dll", + ) + except Exception as e: + success = False + exception = e + +if not success: + os.remove(repaired_wheel_path) + raise exception +else: + print(f"Successfully repaired wheel was written to {repaired_wheel_path}") diff --git a/ci/test_wheels.py b/ci/test_wheels.py new file mode 100644 index 0000000000000..c2fd14287134e --- /dev/null +++ b/ci/test_wheels.py @@ -0,0 +1,58 @@ +import glob +import os +import platform +import shutil +import subprocess +import sys + +py_ver = platform.python_version() +is_32_bit = os.getenv("IS_32_BIT") == "true" +try: + wheel_dir = sys.argv[1] + wheel_path = glob.glob(f"{wheel_dir}/*.whl")[0] +except IndexError: + # Not passed + wheel_path = None +print(f"IS_32_BIT is {is_32_bit}") +print(f"Path to built wheel is {wheel_path}") +if os.name == "nt": + if is_32_bit: + sys.exit(0) # No way to test Windows 32-bit(no docker image) + if wheel_path is None: + raise ValueError("Wheel path must be passed in if on 64-bit Windows") + print(f"Pulling docker image to test Windows 64-bit Python {py_ver}") + subprocess.run(f"docker pull python:{py_ver}-windowsservercore", check=True) + pandas_base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + print(f"pandas project dir is {pandas_base_dir}") + dist_dir = os.path.join(pandas_base_dir, "dist") + print(f"Copying wheel into pandas_base_dir/dist ({dist_dir})") + os.mkdir(dist_dir) + shutil.copy(wheel_path, dist_dir) + print(os.listdir(dist_dir)) + subprocess.run( + rf"docker run -v %cd%:c:\pandas " + f"python:{py_ver}-windowsservercore /pandas/ci/test_wheels_windows.bat", + check=True, + shell=True, + cwd=pandas_base_dir, + ) +else: + import pandas as pd + + pd.test( + extra_args=[ + "-m not clipboard and not single_cpu", + "--skip-slow", + "--skip-network", + "--skip-db", + "-n=2", + ] + ) + pd.test( + extra_args=[ + "-m not clipboard and single_cpu", + "--skip-slow", + "--skip-network", + "--skip-db", + ] + ) diff --git a/ci/test_wheels_windows.bat b/ci/test_wheels_windows.bat new file mode 100644 index 0000000000000..9f4ebdabbf8d1 --- /dev/null +++ b/ci/test_wheels_windows.bat @@ -0,0 +1,9 @@ +set test_command=import pandas as pd; print(pd.__version__); ^ +pd.test(extra_args=['-m not clipboard and not single_cpu', '--skip-slow', '--skip-network', '--skip-db', '-n=2']); ^ +pd.test(extra_args=['-m not clipboard and single_cpu', '--skip-slow', '--skip-network', '--skip-db']) + +python --version +pip install pytz six numpy python-dateutil +pip install hypothesis==6.52.1 pytest>=6.2.5 pytest-xdist pytest-asyncio>=0.17 +pip install --find-links=pandas/dist --no-index pandas +python -c "%test_command%" diff --git a/ci/upload_wheels.sh b/ci/upload_wheels.sh new file mode 100644 index 0000000000000..9b3068def7502 --- /dev/null +++ b/ci/upload_wheels.sh @@ -0,0 +1,42 @@ +# Modified from numpy's https://github.com/numpy/numpy/blob/main/tools/wheels/upload_wheels.sh + +set_upload_vars() { + echo "IS_PUSH is $IS_PUSH" + echo "IS_SCHEDULE_DISPATCH is $IS_SCHEDULE_DISPATCH" + if [[ "$IS_PUSH" == "true" ]]; then + echo push and tag event + export ANACONDA_ORG="multibuild-wheels-staging" + export TOKEN="$NUMPY_STAGING_UPLOAD_TOKEN" + export ANACONDA_UPLOAD="true" + elif [[ "$IS_SCHEDULE_DISPATCH" == "true" ]]; then + echo scheduled or dispatched event + export ANACONDA_ORG="scipy-wheels-nightly" + export TOKEN="$NUMPY_NIGHTLY_UPLOAD_TOKEN" + export ANACONDA_UPLOAD="true" + else + echo non-dispatch event + export ANACONDA_UPLOAD="false" + fi +} +upload_wheels() { + echo ${PWD} + if [[ ${ANACONDA_UPLOAD} == true ]]; then + if [ -z ${TOKEN} ]; then + echo no token set, not uploading + else + conda install -q -y anaconda-client + # sdists are located under dist folder when built through setup.py + if compgen -G "./dist/*.gz"; then + echo "Found sdist" + anaconda -q -t ${TOKEN} upload --skip -u ${ANACONDA_ORG} ./dist/*.gz + elif compgen -G "./wheelhouse/*.whl"; then + echo "Found wheel" + anaconda -q -t ${TOKEN} upload --skip -u ${ANACONDA_ORG} ./wheelhouse/*.whl + else + echo "Files do not exist" + return 1 + fi + echo "PyPI-style index: https://pypi.anaconda.org/$ANACONDA_ORG/simple" + fi + fi +} From eaaf817d3957864133f3ae8500bc30edc2327953 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 30 Aug 2022 09:42:07 -0400 Subject: [PATCH 2/6] update from code review Co-Authored-By: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> --- .github/workflows/wheels.yml | 9 +++++---- ci/upload_wheels.sh | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 64f1f84da9547..f371ec26bf5b7 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -52,7 +52,7 @@ jobs: - [windows-2019, win_amd64] - [windows-2019, win32] # TODO: support PyPy? - python: [["cp38", "3.8"], ["cp39", "3.9"], ["cp310", "3.10"]]# "pp38", "pp39"] + python: [["cp38", "3.8"], ["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"]]# "pp38", "pp39"] env: IS_32_BIT: ${{ matrix.buildplat[1] == 'win32' }} IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} @@ -72,8 +72,7 @@ jobs: uses: pypa/cibuildwheel@v2.9.0 env: CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }} - CIBW_ENVIRONMENT: RUNNER_OS='${{ runner.os }}' - IS_32_BIT='${{ env.IS_32_BIT }}' + CIBW_ENVIRONMENT: IS_32_BIT='${{ env.IS_32_BIT }}' # We can't test directly with cibuildwheel, since we need to have to wheel location # to mount into the docker image CIBW_TEST_COMMAND_LINUX: "python {project}/ci/test_wheels.py" @@ -148,7 +147,9 @@ jobs: - name: Test the sdist run: | # TODO: Don't run test suite, and instead build wheels from sdist - # Depends on pypa/cibuildwheel#1020 + # by splitting the wheel builders into a two stage job + # (1. Generate sdist 2. Build wheels from sdist) + # This tests the sdists, and saves some build time python -m pip install dist/*.gz pip install hypothesis==6.52.1 pytest>=6.2.5 pytest-xdist pytest-asyncio>=0.17 cd .. # Not a good idea to test within the src tree diff --git a/ci/upload_wheels.sh b/ci/upload_wheels.sh index 9b3068def7502..811f0bebaf7da 100644 --- a/ci/upload_wheels.sh +++ b/ci/upload_wheels.sh @@ -6,12 +6,12 @@ set_upload_vars() { if [[ "$IS_PUSH" == "true" ]]; then echo push and tag event export ANACONDA_ORG="multibuild-wheels-staging" - export TOKEN="$NUMPY_STAGING_UPLOAD_TOKEN" + export TOKEN="$PANDAS_STAGING_UPLOAD_TOKEN" export ANACONDA_UPLOAD="true" elif [[ "$IS_SCHEDULE_DISPATCH" == "true" ]]; then echo scheduled or dispatched event export ANACONDA_ORG="scipy-wheels-nightly" - export TOKEN="$NUMPY_NIGHTLY_UPLOAD_TOKEN" + export TOKEN="$PANDAS_NIGHTLY_UPLOAD_TOKEN" export ANACONDA_UPLOAD="true" else echo non-dispatch event From b3b7c8b05cfe1a13d09cdddbd97faf6444218693 Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Tue, 30 Aug 2022 10:13:44 -0400 Subject: [PATCH 3/6] fix 3.11 version --- .github/workflows/wheels.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f371ec26bf5b7..6c0fcae35d8aa 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -52,7 +52,7 @@ jobs: - [windows-2019, win_amd64] - [windows-2019, win32] # TODO: support PyPy? - python: [["cp38", "3.8"], ["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"]]# "pp38", "pp39"] + python: [["cp38", "3.8"], ["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11-dev"]]# "pp38", "pp39"] env: IS_32_BIT: ${{ matrix.buildplat[1] == 'win32' }} IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} @@ -80,6 +80,7 @@ jobs: CIBW_TEST_REQUIRES: hypothesis==6.52.1 pytest>=6.2.5 pytest-xdist pytest-asyncio>=0.17 CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "python ci/fix_wheels.py {wheel} {dest_dir}" CIBW_ARCHS_MACOS: x86_64 universal2 + CIBW_BUILD_VERBOSITY: 3 # Used to push the built wheels - uses: actions/setup-python@v3 From 8c2b38a72b5c4b0115f48e3c388b717497974e0d Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Fri, 2 Sep 2022 15:06:33 -0400 Subject: [PATCH 4/6] changes from code review --- ci/fix_wheels.py | 3 +-- ci/test_wheels.py | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ci/fix_wheels.py b/ci/fix_wheels.py index bb61a5674bbbb..ed7957fac643b 100644 --- a/ci/fix_wheels.py +++ b/ci/fix_wheels.py @@ -1,13 +1,12 @@ import os import shutil -import struct import sys import zipfile try: _, wheel_path, dest_dir = sys.argv # Figure out whether we are building on 32 or 64 bit python - is_32 = struct.calcsize("P") * 8 == 32 + is_32 = sys.maxsize <= 2**32 PYTHON_ARCH = "x86" if is_32 else "x64" except ValueError: # Too many/little values to unpack diff --git a/ci/test_wheels.py b/ci/test_wheels.py index c2fd14287134e..e8f227b0b77dc 100644 --- a/ci/test_wheels.py +++ b/ci/test_wheels.py @@ -5,17 +5,18 @@ import subprocess import sys -py_ver = platform.python_version() -is_32_bit = os.getenv("IS_32_BIT") == "true" -try: - wheel_dir = sys.argv[1] - wheel_path = glob.glob(f"{wheel_dir}/*.whl")[0] -except IndexError: - # Not passed - wheel_path = None -print(f"IS_32_BIT is {is_32_bit}") -print(f"Path to built wheel is {wheel_path}") + if os.name == "nt": + py_ver = platform.python_version() + is_32_bit = os.getenv("IS_32_BIT") == "true" + try: + wheel_dir = sys.argv[1] + wheel_path = glob.glob(f"{wheel_dir}/*.whl")[0] + except IndexError: + # Not passed + wheel_path = None + print(f"IS_32_BIT is {is_32_bit}") + print(f"Path to built wheel is {wheel_path}") if is_32_bit: sys.exit(0) # No way to test Windows 32-bit(no docker image) if wheel_path is None: From 9f4dcf481fa8ea46f423cfee2c99737475a23b1f Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Sat, 10 Sep 2022 15:30:52 -0400 Subject: [PATCH 5/6] Update test_wheels.py --- ci/test_wheels.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/test_wheels.py b/ci/test_wheels.py index e8f227b0b77dc..9a9a6890d8ecb 100644 --- a/ci/test_wheels.py +++ b/ci/test_wheels.py @@ -5,7 +5,6 @@ import subprocess import sys - if os.name == "nt": py_ver = platform.python_version() is_32_bit = os.getenv("IS_32_BIT") == "true" From 2dea43c8e535d3ade3d5eed8570fb76956db0c6d Mon Sep 17 00:00:00 2001 From: Thomas Li <47963215+lithomas1@users.noreply.github.com> Date: Wed, 21 Sep 2022 07:12:13 -0400 Subject: [PATCH 6/6] sync run time with pandas-wheels --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 6c0fcae35d8aa..afd30debee7fb 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -20,7 +20,7 @@ on: # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) # │ │ │ │ │ - - cron: "42 1 * * 4" + - cron: "27 3 */1 * *" push: pull_request: types: [labeled, opened, synchronize, reopened]