Skip to content

allow output of conda recipes with pinned run_constraints - #823

Draft
msarahan wants to merge 3 commits into
conda:mainfrom
msarahan:output-pinned-recipe
Draft

allow output of conda recipes with pinned run_constraints#823
msarahan wants to merge 3 commits into
conda:mainfrom
msarahan:output-pinned-recipe

Conversation

@msarahan

Copy link
Copy Markdown

Description

The motivation here is that we have wanted a way to pin the build environment such that our developers can consciously choose when to fight the fight we all love of adjusting to breaking changes in our dependencies. Pip has PIP_CONSTRAINT, but conda-build and rattler-build don't have equivalents.

The (rough) idea is to use conda-lock to generate the build environment (for us, this will be a superset of all of our projects), and then save that environment as a recipe with everything in the run_constraints dependencies. This metapackage will then be included in the host dependencies for each project, which should have the effect of constraining host dependencies, which will then cascade via run_exports as appropriate.

This also includes a way to filter out some packages from the dependencies, because we only want to pin our dependencies, not our projects. Our projects need to float, as they are changing version with each commit.

It's a little indirect, but I think it might work. I'm attaching a couple of files to show what the anticipated input and output of this code would be. This is a draft, and aside from currently not actually saving recipe files, I'm sure it's rough in other ways. I would not review this too closely (yet?)

input-env.yml.txt

Generated recipe (to be used to build metapackage, which then needs to be uploaded to appropriate channel)

# Generated by conda-lock.
name: rapids-pin
version: 25.08
build:
  string: py313_0
requirements:
  run_constrained:
    - _libgcc_mutex==0.1==conda_forge
    - _openmp_mutex==4.5==2_gnu
    - _python_abi3_support==1.0==hd8ed1ab_2
    - aiohappyeyeballs==2.6.1==pyhd8ed1ab_0
    - aiohttp==3.12.14==py313h3dea7bd_0
    - aiosignal==1.4.0==pyhd8ed1ab_0
    - anyio==4.9.0==pyh29332c3_0
    - aom==3.9.1==hac33072_0
    - argon2-cffi==25.1.0==pyhd8ed1ab_0
    - argon2-cffi-bindings==21.2.0==py313h536fd9c_5
    - arrow==1.3.0==pyhd8ed1ab_1
    - attr==2.5.1==h166bdaf_1
    - attrs==25.3.0==pyh71513ae_0
    - aws-c-auth==0.9.0==h92a005d_16
    - aws-c-cal==0.9.2==he7b75e1_1
    - aws-c-common==0.12.4==hb03c661_0
    - aws-c-compression==0.3.1==h92c474e_6
    - aws-c-event-stream==0.5.5==h0c2b49e_1
    - aws-c-http==0.10.2==hee85082_3
    - aws-c-io==0.21.0==h1d8da38_1
    - aws-c-mqtt==0.13.1==h46c1de9_4
    - aws-c-s3==0.8.4==h9cdc349_0
    - aws-c-sdkutils==0.2.4==h92c474e_1
    - aws-checksums==0.2.7==h92c474e_2
    - aws-crt-cpp==0.33.0==he2a3bdb_1
    - aws-sdk-cpp==1.11.510==h455e09b_15
    - azure-core-cpp==1.15.0==h5cfcd09_0
    - azure-identity-cpp==1.11.0==hb5324b0_1
    - azure-storage-blobs-cpp==12.13.0==hf182047_2
    - azure-storage-common-cpp==12.10.0==h40e822a_1
    - azure-storage-files-datalake-cpp==12.12.0==h141ff2a_2
    - beautifulsoup4==4.13.4==pyha770c72_0
    - bleach==6.2.0==pyh29332c3_4
    - bleach-with-css==6.2.0==h82add2a_4
    - blosc==1.21.6==he440d0b_1
    - bokeh==3.7.3==pyhd8ed1ab_0
    - branca==0.8.1==pyhd8ed1ab_0
    - brotli==1.1.0==hb9d3cd8_3
    - brotli-bin==1.1.0==hb9d3cd8_3
    - brotli-python==1.1.0==py313h46c70d0_3
    - brunsli==0.1==h9c3ff4c_0
    - bzip2==1.0.8==h4bc722e_7
    - c-ares==1.34.5==hb9d3cd8_0
    - c-blosc2==2.19.0==h3122c55_0
    - ca-certificates==2025.7.14==hbd8a1cb_0
    - cached-property==1.5.2==hd8ed1ab_1
    - cached_property==1.5.2==pyha770c72_1
    - cachetools==6.1.0==pyhd8ed1ab_0
    - certifi==2025.7.14==pyhd8ed1ab_0
    - cffi==1.17.1==py313hfab6e84_0
    - charls==2.4.2==h59595ed_0
    - charset-normalizer==3.4.2==pyhd8ed1ab_0
    - click==8.2.1==pyh707e725_0
    - cloudpickle==3.1.1==pyhd8ed1ab_0
    - colorama==0.4.6==pyhd8ed1ab_1
    - colorcet==3.1.0==pyhd8ed1ab_1
    - contourpy==1.3.2==py313h33d0bda_0
    - cpython==3.13.5==py313hd8ed1ab_102
    - cuda-bindings==12.9.0==py313hda822dd_1
    - cuda-cccl_linux-64==12.9.27==ha770c72_0
    - cuda-core==0.3.1==py313he3ad939_0
    - cuda-crt-dev_linux-64==12.9.86==ha770c72_1
    - cuda-crt-tools==12.9.86==ha770c72_1
    - cuda-cudart==12.9.79==h5888daf_0
    - cuda-cudart-dev==12.9.79==h5888daf_0
    - cuda-cudart-dev_linux-64==12.9.79==h3f2d84a_0
    - cuda-cudart-static==12.9.79==h5888daf_0
    - cuda-cudart-static_linux-64==12.9.79==h3f2d84a_0
    - cuda-cudart_linux-64==12.9.79==h3f2d84a_0
    - cuda-nvcc-dev_linux-64==12.9.86==he91c749_1
    - cuda-nvcc-impl==12.9.86==h85509e4_1
    - cuda-nvcc-tools==12.9.86==he02047a_1
    - cuda-nvrtc==12.9.86==h5888daf_0
    - cuda-nvvm-dev_linux-64==12.9.86==ha770c72_1
    - cuda-nvvm-impl==12.9.86==he02047a_1
    - cuda-nvvm-tools==12.9.86==he02047a_1
    - cuda-profiler-api==12.9.79==h7938cbb_0
    - cuda-python==12.9.0==pyhd4762b7_2
    - cuda-version==12.9==h4f385c5_3
    - cupy==13.5.1==py313h586c94b_1
    - cupy-core==13.5.1==py313h9596e46_1
    - custreamz==25.08.00a537==cuda12_py313_250716_da6ce2a9
    - cycler==0.12.1==pyhd8ed1ab_1
    - cyrus-sasl==2.1.28==hd9c7081_0
    - cytoolz==1.0.1==py313h536fd9c_0
    - dask==2025.7.0==pyhe01879c_0
    - dask-core==2025.7.0==pyhe01879c_1
    - dask-cuda==25.08.00a43==py313_250716_7d9e28af
    - datashader==0.18.1==pyhd8ed1ab_0
    - dav1d==1.2.1==hd590300_0
    - defusedxml==0.7.1==pyhd8ed1ab_0
    - distributed==2025.7.0==pyhe01879c_0
    - dlpack==0.8==h59595ed_3
    - exceptiongroup==1.3.0==pyhd8ed1ab_0
    - fastrlock==0.8.3==py313h9800cb9_1
    - folium==0.20.0==pyhd8ed1ab_0
    - fonttools==4.58.5==py313h8060acc_0
    - fqdn==1.5.1==pyhd8ed1ab_1
    - freetype==2.13.3==ha770c72_1
    - freexl==2.0.0==h9dce30a_2
    - frozenlist==1.7.0==py313h6b9daa2_0
    - fsspec==2025.7.0==pyhd8ed1ab_0
    - geopandas==1.1.1==pyhd8ed1ab_0
    - geopandas-base==1.1.1==pyha770c72_0
    - geos==3.13.1==h97f6797_0
    - gflags==2.2.2==h5888daf_1005
    - giflib==5.2.2==hd590300_0
    - glog==0.7.1==hbabe93e_0
    - h2==4.2.0==pyhd8ed1ab_0
    - holoviews==1.21.0==pyhd8ed1ab_0
    - hpack==4.1.0==pyhd8ed1ab_0
    - hyperframe==6.1.0==pyhd8ed1ab_0
    - icu==75.1==he02047a_0
    - idna==3.10==pyhd8ed1ab_1
    - imagecodecs==2025.3.30==py313h8b391ee_2
    - imageio==2.37.0==pyhfb79c49_0
    - importlib-metadata==8.7.0==pyhe01879c_1
    - importlib_resources==6.5.2==pyhd8ed1ab_0
    - isoduration==20.11.0==pyhd8ed1ab_1
    - jinja2==3.1.6==pyhd8ed1ab_0
    - joblib==1.5.1==pyhd8ed1ab_0
    - json-c==0.18==h6688a6e_0
    - jsonpointer==3.0.0==py313h78bf25f_1
    - jsonschema==4.24.0==pyhd8ed1ab_0
    - jsonschema-specifications==2025.4.1==pyh29332c3_0
    - jsonschema-with-format-nongpl==4.24.0==hd8ed1ab_0
    - jupyter-server-proxy==4.4.0==pyhd8ed1ab_1
    - jupyter_client==8.6.3==pyhd8ed1ab_1
    - jupyter_core==5.8.1==pyh31011fe_0
    - jupyter_events==0.12.0==pyh29332c3_0
    - jupyter_server==2.16.0==pyhe01879c_0
    - jupyter_server_terminals==0.5.3==pyhd8ed1ab_1
    - jupyterlab_pygments==0.3.0==pyhd8ed1ab_2
    - jxrlib==1.1==hd590300_3
    - keyutils==1.6.1==h166bdaf_0
    - kiwisolver==1.4.8==py313h33d0bda_1
    - krb5==1.21.3==h659f571_0
    - lazy-loader==0.4==pyhd8ed1ab_2
    - lazy_loader==0.4==pyhd8ed1ab_2
    - lcms2==2.17==h717163a_0
    - ld_impl_linux-64==2.44==h1423503_1
    - lerc==4.0.0==h0aef613_1
    - libabseil==20250512.1==cxx17_hba17884_0
    - libaec==1.1.4==h3f801dc_0
    - libarchive==3.8.1==gpl_h98cc613_100
    - libarrow==19.0.1==h94aa55a_22_cpu
    - libarrow-acero==19.0.1==h635bf11_22_cpu
    - libarrow-dataset==19.0.1==h635bf11_22_cpu
    - libarrow-substrait==19.0.1==h3f74fd7_22_cpu
    - libavif16==1.3.0==h766b0b6_0
    - libblas==3.9.0==32_h59b9bed_openblas
    - libbrotlicommon==1.1.0==hb9d3cd8_3
    - libbrotlidec==1.1.0==hb9d3cd8_3
    - libbrotlienc==1.1.0==hb9d3cd8_3
    - libcap==2.75==h39aace5_0
    - libcblas==3.9.0==32_he106b2a_openblas
    - libcrc32c==1.1.2==h9c3ff4c_0
    - libcublas==12.9.1.4==h9ab20c4_0
    - libcublas-dev==12.9.1.4==h9ab20c4_0
    - libcufft==11.4.1.4==h5888daf_0
    - libcufile==1.14.1.1==ha8da6e3_0
    - libcufile-dev==1.14.1.1==h5888daf_0
    - libcurand==10.3.10.19==h9ab20c4_0
    - libcurand-dev==10.3.10.19==h9ab20c4_0
    - libcurl==8.14.1==h332b0f4_0
    - libcusolver==11.7.5.82==h9ab20c4_1
    - libcusolver-dev==11.7.5.82==h9ab20c4_1
    - libcusparse==12.5.10.65==h5888daf_1
    - libcusparse-dev==12.5.10.65==h5888daf_1
    - libdeflate==1.24==h86f0d12_0
    - libedit==3.1.20250104==pl5321h7949ede_0
    - libev==4.33==hd590300_2
    - libevent==2.1.12==hf998b51_1
    - libexpat==2.7.0==h5888daf_0
    - libffi==3.4.6==h2dba641_1
    - libfreetype==2.13.3==ha770c72_1
    - libfreetype6==2.13.3==h48d6fc4_1
    - libgcc==15.1.0==h767d61c_3
    - libgcc-ng==15.1.0==h69a702a_3
    - libgcrypt-lib==1.11.1==hb9d3cd8_0
    - libgdal-core==3.11.3==ha8f0914_0
    - libgfortran==15.1.0==h69a702a_3
    - libgfortran5==15.1.0==hcea5267_3
    - libgomp==15.1.0==h767d61c_3
    - libgoogle-cloud==2.39.0==hdb79228_0
    - libgoogle-cloud-storage==2.39.0==hdbdcf42_0
    - libgpg-error==1.55==h3f2d84a_0
    - libgrpc==1.73.1==h1e535eb_0
    - libhwy==1.2.0==hf40a0c7_0
    - libiconv==1.18==h4ce23a2_1
    - libjpeg-turbo==3.1.0==hb9d3cd8_0
    - libjxl==0.11.1==h7b0646d_2
    - libkml==1.3.0==hf539b9f_1021
    - libkvikio==25.08.00a52==cuda12_9_250716_54c420a6
    - liblapack==3.9.0==32_h7ac8fdf_openblas
    - liblzma==5.8.1==hb9d3cd8_2
    - libmpdec==4.0.0==hb9d3cd8_0
    - libnghttp2==1.64.0==h161d5f1_0
    - libnl==3.11.0==hb9d3cd8_0
    - libnsl==2.0.1==hb9d3cd8_1
    - libntlm==1.8==hb9d3cd8_0
    - libnuma==2.0.18==hb9d3cd8_3
    - libnvjitlink==12.9.86==h5888daf_1
    - libnvjpeg==12.4.0.76==h5888daf_0
    - libopenblas==0.3.30==pthreads_h94d23a6_0
    - libopentelemetry-cpp==1.21.0==hb9b0907_1
    - libopentelemetry-cpp-headers==1.21.0==ha770c72_1
    - libparquet==19.0.1==h790f06f_22_cpu
    - libpng==1.6.50==h943b412_0
    - libprotobuf==6.31.1==h9ef548d_1
    - librdkafka==2.8.0==h2e2c4f7_0
    - libre2-11==2025.06.26==h7064273_1
    - librttopo==1.1.0==hd718a1a_18
    - libsodium==1.0.20==h4ab18f5_0
    - libspatialite==5.1.0==he17ca71_14
    - libsqlite==3.50.2==hee844dc_2
    - libssh2==1.11.1==hcf80075_0
    - libstdcxx==15.1.0==h8f9b012_3
    - libstdcxx-ng==15.1.0==h4852527_3
    - libsystemd0==257.7==h4e0b6ca_0
    - libthrift==0.22.0==h093b73b_0
    - libtiff==4.7.0==hf01ce69_5
    - libudev1==257.7==hbe16f8c_0
    - libutf8proc==2.10.0==h202a827_0
    - libuuid==2.38.1==h0b41bf4_0
    - libuv==1.51.0==hb9d3cd8_0
    - libwebp-base==1.6.0==hd42ef1d_0
    - libxcb==1.17.0==h8a09558_0
    - libxcrypt==4.4.36==hd590300_1
    - libxgboost==3.0.2==rapidsai_haf472e3_0
    - libxml2==2.13.8==h4bc477f_0
    - libzlib==1.3.1==hb9d3cd8_2
    - libzopfli==1.0.3==h9c3ff4c_0
    - linkify-it-py==2.0.3==pyhd8ed1ab_1
    - llvmlite==0.44.0==py313h1b76d92_1
    - locket==1.0.0==pyhd8ed1ab_0
    - lz4==4.4.4==py313h8756d67_0
    - lz4-c==1.10.0==h5888daf_1
    - lzo==2.10==hd590300_1001
    - mapclassify==2.10.0==pyhd8ed1ab_1
    - markdown==3.8.2==pyhd8ed1ab_0
    - markdown-it-py==3.0.0==pyhd8ed1ab_1
    - markupsafe==3.0.2==py313h8060acc_1
    - matplotlib-base==3.10.3==py313h129903b_0
    - mdit-py-plugins==0.4.2==pyhd8ed1ab_1
    - mdurl==0.1.2==pyhd8ed1ab_1
    - minizip==4.0.10==h05a5f5f_0
    - mistune==3.1.3==pyh29332c3_0
    - msgpack-python==1.1.1==py313h33d0bda_0
    - multidict==6.6.3==py313h8060acc_0
    - multipledispatch==0.6.0==pyhd8ed1ab_1
    - munkres==1.1.4==pyhd8ed1ab_1
    - muparser==2.3.5==h5888daf_0
    - narwhals==1.47.0==pyhe01879c_0
    - nbclient==0.10.2==pyhd8ed1ab_0
    - nbconvert-core==7.16.6==pyh29332c3_0
    - nbformat==5.10.4==pyhd8ed1ab_1
    - nccl==2.27.6.1==h9b8ff78_0
    - ncurses==6.5==h2d0b736_3
    - networkx==3.5==pyhe01879c_0
    - nlohmann_json==3.12.0==h3f2d84a_0
    - nodejs==24.4.0==heeeca48_0
    - numba==0.61.2==py313h50b8c88_1
    - numba-cuda==0.16.0==pyh59d5780_0
    - numpy==2.2.6==py313h17eae1a_0
    - nvcomp==4.2.0.11==h791f646_1
    - nvidia-ml-py==12.575.51==pyhd8ed1ab_0
    - nvtx==0.2.12==py313h536fd9c_0
    - openjpeg==2.5.3==h5fbd93e_0
    - openssl==3.5.1==h7b32b05_0
    - orc==2.1.3==h61e0c1e_0
    - overrides==7.7.0==pyhd8ed1ab_1
    - packaging==25.0==pyh29332c3_1
    - pandas==2.3.1==py313h08cd8bf_0
    - pandocfilters==1.5.0==pyhd8ed1ab_0
    - panel==1.7.4==pyhd8ed1ab_0
    - param==2.2.1==pyhd8ed1ab_0
    - partd==1.4.2==pyhd8ed1ab_0
    - pcre2==10.45==hc749103_0
    - pillow==11.3.0==py313h8db990d_0
    - pkgutil-resolve-name==1.3.10==pyhd8ed1ab_2
    - platformdirs==4.3.8==pyhe01879c_0
    - polars==1.31.0==default_h70f2ef1_1
    - polars-default==1.31.0==py39hf521cc8_1
    - proj==9.6.2==h0054346_0
    - prometheus-cpp==1.3.0==ha5d0236_0
    - prometheus_client==0.22.1==pyhd8ed1ab_0
    - propcache==0.3.1==py313h8060acc_0
    - psutil==7.0.0==py313h536fd9c_0
    - pthread-stubs==0.4==hb9d3cd8_1002
    - ptyprocess==0.7.0==pyhd8ed1ab_1
    - py-xgboost==3.0.2==rapidsai_pyh7b92683_0
    - pyarrow==19.0.1==py313h78bf25f_0
    - pyarrow-core==19.0.1==py313he5f92c8_0_cpu
    - pycparser==2.22==pyh29332c3_1
    - pyct==0.5.0==pyhd8ed1ab_1
    - pygments==2.19.2==pyhd8ed1ab_0
    - pynvml==12.0.0==pyhd8ed1ab_0
    - pyogrio==0.11.0==py313hf96fbec_1
    - pyparsing==3.2.3==pyhd8ed1ab_1
    - pyproj==3.7.1==py313hcd509b5_1
    - pysocks==1.7.1==pyha55dd90_7
    - python==3.13.5==hec9711d_102_cp313
    - python-confluent-kafka==2.8.0==py313h536fd9c_0
    - python-dateutil==2.9.0.post0==pyhe01879c_2
    - python-fastjsonschema==2.21.1==pyhd8ed1ab_0
    - python-gil==3.13.5==h4df99d1_102
    - python-json-logger==2.0.7==pyhd8ed1ab_0
    - python-tzdata==2025.2==pyhd8ed1ab_0
    - python_abi==3.13==7_cp313
    - pytz==2025.2==pyhd8ed1ab_0
    - pyviz_comms==3.0.6==pyhd8ed1ab_0
    - pywavelets==1.8.0==py313ha014f3b_0
    - pyyaml==6.0.2==py313h8060acc_2
    - pyzmq==27.0.0==py313h8e95178_0
    - qhull==2020.2==h434a139_5
    - rav1e==0.7.1==h8fae777_3
    - rdma-core==58.0==h5888daf_0
    - re2==2025.06.26==h9925aae_1
    - readline==8.2==h8c095d6_2
    - referencing==0.36.2==pyh29332c3_0
    - requests==2.32.4==pyhd8ed1ab_0
    - rfc3339-validator==0.1.4==pyhd8ed1ab_1
    - rfc3986-validator==0.1.1==pyh9f0ad1d_0
    - rich==14.0.0==pyh29332c3_0
    - rpds-py==0.26.0==py313h4b2b08d_0
    - s2n==1.5.22==h96f233e_0
    - scikit-image==0.24.0==py313ha87cce1_3
    - scikit-learn==1.7.0==py313h8ef605b_1
    - scipy==1.16.0==py313h86fcf2b_0
    - send2trash==1.8.3==pyh0d859eb_1
    - setuptools==80.9.0==pyhff2d567_0
    - shapely==2.1.1==py313h576e190_0
    - simpervisor==1.0.0==pyhd8ed1ab_1
    - six==1.17.0==pyhd8ed1ab_0
    - snappy==1.2.1==h8bd8927_1
    - sniffio==1.3.1==pyhd8ed1ab_1
    - sortedcontainers==2.4.0==pyhd8ed1ab_1
    - soupsieve==2.7==pyhd8ed1ab_0
    - sqlite==3.50.2==heff268d_2
    - streamz==0.6.4==pyhd8ed1ab_1
    - svt-av1==3.0.2==h5888daf_0
    - tblib==3.1.0==pyhd8ed1ab_0
    - terminado==0.18.1==pyh0d859eb_0
    - threadpoolctl==3.6.0==pyhecae5ae_0
    - tifffile==2025.6.11==pyhd8ed1ab_0
    - tinycss2==1.4.0==pyhd8ed1ab_0
    - tk==8.6.13==noxft_hd72426e_102
    - toolz==1.0.0==pyhd8ed1ab_1
    - tornado==6.5.1==py313h536fd9c_0
    - tqdm==4.67.1==pyhd8ed1ab_1
    - traitlets==5.14.3==pyhd8ed1ab_1
    - treelite==4.4.1==py313ha8a5e75_1
    - types-python-dateutil==2.9.0.20250708==pyhd8ed1ab_0
    - typing-extensions==4.14.1==h4440ef1_0
    - typing_extensions==4.14.1==pyhe01879c_0
    - typing_utils==0.1.0==pyhd8ed1ab_1
    - tzdata==2025b==h78e105d_0
    - uc-micro-py==1.0.3==pyhd8ed1ab_1
    - ucx==1.18.1==h8c7ad85_1
    - uri-template==1.3.0==pyhd8ed1ab_1
    - uriparser==0.9.8==hac33072_0
    - urllib3==2.5.0==pyhd8ed1ab_0
    - webcolors==24.11.1==pyhd8ed1ab_0
    - webencodings==0.5.1==pyhd8ed1ab_3
    - websocket-client==1.8.0==pyhd8ed1ab_1
    - xarray==2025.7.1==pyhd8ed1ab_0
    - xerces-c==3.2.5==h988505b_2
    - xgboost==3.0.2==rapidsai_pyh452a892_0
    - xorg-libxau==1.0.12==hb9d3cd8_0
    - xorg-libxdmcp==1.1.5==hb9d3cd8_0
    - xyzservices==2025.4.0==pyhd8ed1ab_0
    - yaml==0.2.5==h7f98852_2
    - yarl==1.20.1==py313h8060acc_0
    - zeromq==4.3.5==h3b0a872_7
    - zfp==1.0.1==h5888daf_2
    - zict==3.0.0==pyhd8ed1ab_1
    - zipp==3.23.0==pyhd8ed1ab_0
    - zlib==1.3.1==hb9d3cd8_2
    - zlib-ng==2.2.4==h7955e40_0
    - zstandard==0.23.0==py313h536fd9c_2
    - zstd==1.5.7==hb8e6e7a_2
about:
  summary: A pinning package for a rapids-pin environment, to be used as a set of constraints at build time for other recipes.

@netlify

netlify Bot commented Jul 16, 2025

Copy link
Copy Markdown

Deploy Preview for conda-lock ready!

Name Link
🔨 Latest commit 2aa45fa
🔍 Latest deploy log https://app.netlify.com/projects/conda-lock/deploys/687abafdb580da0008235014
😎 Deploy Preview https://deploy-preview-823--conda-lock.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@maresb

maresb commented Jul 17, 2025

Copy link
Copy Markdown
Contributor

Wow, that's quite an elaborate scheme! 😂

Good luck with the implementation, and let me know when you'd like me to take a look. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants