AndrewZhaoLuo commented on a change in pull request #10056:
URL: https://github.com/apache/tvm/pull/10056#discussion_r792186132



##########
File path: tests/scripts/update_tag.py
##########
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+# 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.
+
+import os
+import json
+import argparse
+import tempfile
+from typing import Any, Dict
+
+from git_utils import git, GitHubRepo, parse_remote
+
+
+_commit_query_fields = """
+    messageHeadline
+    oid
+    statusCheckRollup {
+        contexts(last:100) {
+            nodes {
+                ... on CheckRun {
+                    conclusion
+                    status
+                    name
+                    checkSuite {
+                        workflowRun {
+                            workflow {
+                                name
+                            }
+                        }
+                    }
+                }
+                ... on StatusContext {
+                    context
+                    state
+                }
+            }
+        }
+    }
+"""
+
+
+def commits_query(user: str, repo: str, cursor: str = None):
+    """
+    Create a GraphQL query to find the last N commits along with their statuses
+    and some metadata (paginated after 'cursor')
+    """
+    after = ""
+    if cursor is not None:
+        after = f', after:"{cursor}"'
+
+    return f"""
+    {{
+    repository(name: "{repo}", owner: "{user}") {{
+        defaultBranchRef {{
+        target {{
+            ... on Commit {{
+            history(first: 15{after}) {{
+                edges {{ cursor }}
+                nodes {{
+                    {_commit_query_fields}
+                }}
+            }}
+            }}
+        }}
+        }}
+    }}
+    }}
+    """
+
+
+def commit_passed_ci(commit: Dict[str, Any]) -> bool:
+    """
+    Returns true if all of a commit's statuses are SUCCESS
+    """
+    statuses = commit["statusCheckRollup"]["contexts"]["nodes"]
+
+    # GitHub Actions statuses are different from external GitHub statuses, so
+    # unify them into 1 representation
+    unified_statuses = []
+    for status in statuses:
+        if "context" in status:
+            # Parse non-GHA status
+            unified_statuses.append((status["context"], status["state"] == 
"SUCCESS"))
+        else:
+            # Parse GitHub Actions item
+            workflow = status["checkSuite"]["workflowRun"]["workflow"]["name"]
+            name = f"{workflow} / {status['name']}"
+            unified_statuses.append((name, status["conclusion"] == "SUCCESS"))
+
+    print(f"Statuses on {commit['oid']}:", json.dumps(unified_statuses, 
indent=2))
+
+    # Assert that specific jobs are present in the commit statuses (i.e. don't
+    # approve if CI was broken and didn't schedule a job)
+    expected_jobs = {"tvm-ci/branch"}
+    job_names = {name for name, status in unified_statuses}
+    for job in expected_jobs:
+        if job not in job_names:
+            # Did not find expected job name
+            return False
+
+    passed_ci = all(status for name, status in unified_statuses)
+    return passed_ci
+
+
+def update_tag(user: str, repo: str, sha: str, tag_name: str, message: str) -> 
None:
+    with tempfile.TemporaryDirectory() as f:
+        # Clone only a specific commit: https://stackoverflow.com/a/3489576
+        git(["init"], cwd=f)
+        git(["remote", "add", "origin", f"[email protected]:{user}/{repo}.git"], 
cwd=f)
+        git(["fetch", "origin", sha], cwd=f)
+        git(["reset", "--hard", "FETCH_HEAD"], cwd=f)
+
+        # Create a push the tag
+        git(["tag", "--annotate", tag_name, f"--message={message}"], cwd=f)
+        git(["push", "origin", "--force", tag_name], cwd=f)
+        print(f"Pushed tag {tag_name} with commit {sha}")
+
+
+if __name__ == "__main__":
+    help = "Push the a tag to the last commit that passed all CI runs"
+    parser = argparse.ArgumentParser(description=help)
+    parser.add_argument("--remote", default="origin", help="ssh remote to 
parse")
+    parser.add_argument("--dry-run", action="store_true", help="don't submit 
to GitHub")
+    parser.add_argument("--tag", default="last-successful", help="tag name")
+    parser.add_argument(
+        "--message", default="last 'main' commit that passed CI", help="label 
to add"
+    )
+    parser.add_argument("--json", help="(testing) data to use instead of 
fetching from GitHub")
+    args = parser.parse_args()
+
+    remote = git(["config", "--get", f"remote.{args.remote}.url"])
+    user, repo = parse_remote(remote)
+
+    if args.json:
+        r = json.loads(args.json)
+    else:
+        github = GitHubRepo(token=os.environ["GITHUB_TOKEN"], user=user, 
repo=repo)
+        q = commits_query(user, repo)
+        r = github.graphql(q)
+
+    commits = 
r["data"]["repository"]["defaultBranchRef"]["target"]["history"]["nodes"]
+
+    # Limit GraphQL pagination
+    MAX_COMMITS_TO_CHECK = 50
+    i = 0
+
+    while i < MAX_COMMITS_TO_CHECK:
+        # Check each commit
+        for commit in commits:
+            if commit_passed_ci(commit):
+                print(f"Found last good commit: {commit['oid']}: 
{commit['messageHeadline']}")
+                if not args.dry_run:
+                    update_tag(
+                        user="driazati",

Review comment:
       probably want to uncomment this :P 




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to