This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new ad90316f9 ci: ensure GitHub Actions and pre-commit hooks are pinned 
(#2576)
ad90316f9 is described below

commit ad90316f9fede252ca56ff343a116325549f9573
Author: David Li <[email protected]>
AuthorDate: Wed Mar 12 21:57:04 2025 -0400

    ci: ensure GitHub Actions and pre-commit hooks are pinned (#2576)
    
    Apache wants us to limit concurrency, ensure actions are pinned, and
    ensure we aren't exporting GITHUB_TOKEN etc.
    (https://infra.apache.org/github-actions-policy.html) It's not clear to
    me if our use of GITHUB_TOKEN in dev_pr.yaml falls under that.
    
    Fixes #2575.
    
    ---------
    
    Co-authored-by: Sutou Kouhei <[email protected]>
---
 .github/workflows/dev_adbc.yml       |   2 +-
 .github/workflows/integration.yml    |   8 +--
 .github/workflows/native-unix.yml    |  18 +++---
 .github/workflows/native-windows.yml |   8 +--
 .github/workflows/nightly-verify.yml |   2 +-
 .github/workflows/packaging.yml      |   8 +--
 .github/workflows/r-check.yml        |   4 +-
 .github/workflows/r-extended.yml     |   2 +-
 .github/workflows/verify.yml         |   2 +-
 .pre-commit-config.yaml              |  27 ++++++---
 ci/scripts/run_pre_commit_pin.py     | 109 +++++++++++++++++++++++++++++++++++
 11 files changed, 154 insertions(+), 36 deletions(-)

diff --git a/.github/workflows/dev_adbc.yml b/.github/workflows/dev_adbc.yml
index 817166a12..a841c7e7b 100644
--- a/.github/workflows/dev_adbc.yml
+++ b/.github/workflows/dev_adbc.yml
@@ -55,7 +55,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
diff --git a/.github/workflows/integration.yml 
b/.github/workflows/integration.yml
index 407650ffc..18d57c721 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -68,7 +68,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -118,7 +118,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -187,7 +187,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -287,7 +287,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
diff --git a/.github/workflows/native-unix.yml 
b/.github/workflows/native-unix.yml
index 1b08add18..23eadd5de 100644
--- a/.github/workflows/native-unix.yml
+++ b/.github/workflows/native-unix.yml
@@ -95,7 +95,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -173,7 +173,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -283,7 +283,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -329,7 +329,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -392,7 +392,7 @@ jobs:
         with:
           fetch-depth: 0
           persist-credentials: false
-      - uses: 'google-github-actions/auth@v2'
+      - uses: 
google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935  # v2.1.8
         continue-on-error: true # if auth fails, bigquery driver tests should 
skip
         with:
           workload_identity_provider: ${{ 
secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
@@ -449,7 +449,7 @@ jobs:
         with:
           fetch-depth: 0
           persist-credentials: false
-      - uses: 'google-github-actions/auth@v2'
+      - uses: 
google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935  # v2.1.8
         continue-on-error: true # if auth fails, bigquery driver tests should 
skip
         with:
           workload_identity_provider: ${{ 
secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
@@ -465,7 +465,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -549,7 +549,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -659,7 +659,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
diff --git a/.github/workflows/native-windows.yml 
b/.github/workflows/native-windows.yml
index 6f02d327a..a0383a7ff 100644
--- a/.github/workflows/native-windows.yml
+++ b/.github/workflows/native-windows.yml
@@ -79,7 +79,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-mamba: true
@@ -134,7 +134,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-mamba: true
@@ -204,7 +204,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-mamba: true
@@ -268,7 +268,7 @@ jobs:
         with:
           path: ~/conda_pkgs_dir
           key: conda-${{ runner.os }}-${{ steps.get-date.outputs.today }}-${{ 
env.CACHE_NUMBER }}-${{ hashFiles('ci/**') }}
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-mamba: true
diff --git a/.github/workflows/nightly-verify.yml 
b/.github/workflows/nightly-verify.yml
index db79e7c34..a689ccf7f 100644
--- a/.github/workflows/nightly-verify.yml
+++ b/.github/workflows/nightly-verify.yml
@@ -135,7 +135,7 @@ jobs:
         run: |
           mv apache-arrow-adbc-${{ env.VERSION }}-rc0/KEYS .
 
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         # The Unix script will set up conda itself
         if: matrix.os == 'windows-latest'
         with:
diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml
index 1a1d2f89c..4ff85b25e 100644
--- a/.github/workflows/packaging.yml
+++ b/.github/workflows/packaging.yml
@@ -342,7 +342,7 @@ jobs:
           mv apache-arrow-adbc-$VERSION.tar.gz adbc/ci/linux-packages/
 
       - name: Set up Ruby
-        uses: ruby/setup-ruby@v1
+        uses: ruby/setup-ruby@32110d4e311bd8996b2a82bf2a43b714ccc91777  # 
v1.221.0
         with:
           ruby-version: ruby
 
@@ -354,7 +354,7 @@ jobs:
           restore-keys: linux-${{ env.TASK_NAMESPACE }}-ccache-${{ 
matrix.target }}-
 
       - name: Login to GitHub Container registry
-        uses: docker/login-action@v3
+        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567  # 
v3.3.0
         with:
           registry: ghcr.io
           username: ${{ github.actor }}
@@ -519,7 +519,7 @@ jobs:
           echo "schedule: ${{ github.event.schedule }}" >> $GITHUB_STEP_SUMMARY
           echo "ref: ${{ github.ref }}" >> $GITHUB_STEP_SUMMARY
 
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
@@ -1061,7 +1061,7 @@ jobs:
         uses: actions/download-artifact@v4
         with:
           path: conda-packages
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         with:
           miniforge-version: latest
           use-only-tar-bz2: false
diff --git a/.github/workflows/r-check.yml b/.github/workflows/r-check.yml
index cc4cd9b7c..08a5fe60e 100644
--- a/.github/workflows/r-check.yml
+++ b/.github/workflows/r-check.yml
@@ -47,7 +47,7 @@ jobs:
       - uses: actions/setup-go@v5
         with:
           go-version: "${{ env.GO_VERSION }}"
-      - uses: r-lib/actions/setup-r@v2
+      - uses: r-lib/actions/setup-r@14a7e741c1cb130261263aa1593718ba42cf443b  
# v2
         with:
           r-version: release
           use-public-rspm: true
@@ -94,7 +94,7 @@ jobs:
           ADBC_FLIGHTSQL_TEST_URI="grpc://localhost:8080"
           echo "ADBC_FLIGHTSQL_TEST_URI=${ADBC_FLIGHTSQL_TEST_URI}" >> 
$GITHUB_ENV
 
-      - uses: r-lib/actions/check-r-package@v2
+      - uses: 
r-lib/actions/check-r-package@14a7e741c1cb130261263aa1593718ba42cf443b  # v2
         env:
           ADBC_SNOWFLAKE_TEST_URI: ${{ secrets.SNOWFLAKE_URI }}
           R_KEEP_PKG_SOURCE: yes
diff --git a/.github/workflows/r-extended.yml b/.github/workflows/r-extended.yml
index 1ca2e821c..088b301a1 100644
--- a/.github/workflows/r-extended.yml
+++ b/.github/workflows/r-extended.yml
@@ -108,7 +108,7 @@ jobs:
 
     steps:
       - uses: actions/checkout@v4
-      - uses: r-lib/actions/setup-r@v2
+      - uses: r-lib/actions/setup-r@14a7e741c1cb130261263aa1593718ba42cf443b  
# v2
         with:
           rversion: ${{ matrix.rversion }}
           use-public-rspm: true
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 7c8230e57..f08cb00f3 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -87,7 +87,7 @@ jobs:
           fetch-depth: 0
           persist-credentials: false
           submodules: recursive
-      - uses: conda-incubator/setup-miniconda@v3
+      - uses: 
conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830  # 
v3.1.1
         # The Unix script will set up conda itself
         if: matrix.os == 'windows-latest'
         with:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f56926f6a..f20c4aa57 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -40,12 +40,12 @@ repos:
     - id: trailing-whitespace
       exclude: "^r/.*?/_snaps/.*?.md$"
   - repo: https://github.com/pre-commit/mirrors-clang-format
-    rev: "v18.1.7"
+    rev: deec0115cd2847f837ac9180c4b7d1edb423fe02  # v18.1.7
     hooks:
       - id: clang-format
         types_or: [c, c++]
   - repo: https://github.com/cheshirekow/cmake-format-precommit
-    rev: v0.6.13
+    rev: e2c2116d86a80e72e7146a06e68b7c228afc6319  # v0.6.13
     hooks:
     - id: cmake-format
       args: [--in-place]
@@ -60,13 +60,13 @@ repos:
         - "--linelength=90"
         - "--verbose=2"
   - repo: https://github.com/golangci/golangci-lint
-    rev: v1.64.5
+    rev: 0a603e49e5e9870f5f9f2035bcbe42cd9620a9d5  # v1.64.5
     hooks:
     - id: golangci-lint
       entry: bash -c 'cd go/adbc && golangci-lint run --fix --timeout 5m'
       types_or: [go, go-mod]
   - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
-    rev: v2.14.0
+    rev: a6273196190bb0f68caf1dc68073cf62c719f725  # v2.14.0
     hooks:
     - id: pretty-format-golang
       args: [--autofix]
@@ -75,22 +75,22 @@ repos:
       args: [--autofix]
       types_or: [java]
   - repo: https://github.com/psf/black
-    rev: 25.1.0
+    rev: 8a737e727ac5ab2f1d4cf5876720ed276dc8dc4b  # 25.1.0
     hooks:
     - id: black
       types_or: [pyi, python]
   - repo: https://github.com/PyCQA/flake8
-    rev: 7.1.2
+    rev: bddd87797f8dfc07d2a10c894776018d9bec590b  # 7.1.2
     hooks:
     - id: flake8
       types_or: [python]
   - repo: https://github.com/PyCQA/isort
-    rev: 6.0.0
+    rev: 0a0b7a830386ba6a31c2ec8316849ae4d1b8240d  # 6.0.0
     hooks:
     - id: isort
       types_or: [python]
   - repo: https://github.com/MarcoGorelli/cython-lint
-    rev: v0.16.2
+    rev: 9247866fce7128f2c0eaf4a09f437880397d4689  # v0.16.2
     hooks:
     - id: cython-lint
   - repo: https://github.com/vala-lang/vala-lint
@@ -110,8 +110,17 @@ repos:
       pass_filenames: true
       files: '^c/include/arrow-adbc/.*\.h$'
       entry: "./ci/scripts/run_cgo_drivermgr_check.sh"
+    # https://infra.apache.org/github-actions-policy.html
+    - id: check-pin
+      name: Ensure GitHub Actions and pre-commit hooks are pinned to a 
specific SHA
+      language: python
+      additional_dependencies:
+        - "ruamel.yaml==0.18.7"
+      pass_filenames: true
+      files: 
'(^\.pre-commit-config\.yaml$)|(^\.github/workflows/.*\.(yml|yaml)$)'
+      entry: "./ci/scripts/run_pre_commit_pin.py"
   - repo: https://github.com/doublify/pre-commit-rust
-    rev: v1.0
+    rev: eeee35a89e69d5772bdee97db1a6a898467b686e  # v1.0
     hooks:
     - id: fmt
       name: rustfmt
diff --git a/ci/scripts/run_pre_commit_pin.py b/ci/scripts/run_pre_commit_pin.py
new file mode 100755
index 000000000..9717d8acc
--- /dev/null
+++ b/ci/scripts/run_pre_commit_pin.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Validate that pre-commit repos are pinned to a commit hash."""
+
+import argparse
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+from ruamel.yaml import YAML
+
+
+def resolve_repo(repo: str, tag: str, cache: dict[tuple[str, str], str]) -> 
str:
+    key = (repo, tag)
+    if key in cache:
+        return cache[key]
+
+    ls_remote = subprocess.check_output(
+        [
+            "git",
+            "ls-remote",
+            repo,
+            f"refs/tags/{tag}",
+        ],
+        text=True,
+    )
+    sha, _ = ls_remote.strip().split(maxsplit=1)
+    cache[key] = sha
+    return sha
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("files", nargs="+", type=Path)
+    args = parser.parse_args()
+
+    sha_re = re.compile(r"^[0-9a-f]{40}$")
+    ret = 0
+    yaml = YAML(typ="rt")
+    resolved = {}
+
+    for path in args.files:
+        print("Checking", path)
+        with path.open() as source:
+            data = yaml.load(source)
+
+        if path.name == ".pre-commit-config.yaml":
+            for repo in data["repos"]:
+                # import code; code.interact(local=locals())
+                # return 1
+                rev = repo.get("rev")
+                if rev is None:
+                    if repo["repo"] != "local":
+                        print("repo is missing `rev:`")
+                        print("- repo:", repo["repo"])
+                        ret += 1
+                elif not sha_re.match(rev):
+                    sha = resolve_repo(repo["repo"], rev, resolved)
+                    print("`rev` should be a commit hash:")
+                    print("- repo:", repo["repo"])
+                    print("  rev:", sha, " #", repo["rev"])
+                    ret += 1
+        else:
+            # GitHub Actions
+            for key, job in data["jobs"].items():
+                if "steps" not in job:
+                    continue
+
+                for step in job["steps"]:
+                    if "uses" not in step:
+                        continue
+                    action, _, rev = step["uses"].partition("@")
+                    repo = "/".join(action.split("/", maxsplit=2)[:2])
+                    if not sha_re.match(rev):
+                        if (
+                            repo.startswith("actions/")
+                            or repo.startswith("apache/")
+                            or repo.startswith("github/")
+                        ):
+                            # GitHub-provided actions don't _have_ to be pinned
+                            continue
+
+                        sha = resolve_repo(f"https://github.com/{repo}";, rev, 
resolved)
+                        print(step["uses"], "should be pinned:")
+                        print(f"{action}@{sha}  # {rev}")
+                        ret += 1
+
+    return ret
+
+
+if __name__ == "__main__":
+    sys.exit(main())

Reply via email to