[diffusion] CI: change ground truth upload path and improve publish script (#24120)
This commit is contained in:
@@ -14,7 +14,12 @@ on:
|
||||
default: ''
|
||||
type: string
|
||||
output_name:
|
||||
description: 'Custom output folder name (also used for artifact names and publish target dir). Leave empty to use defaults.'
|
||||
description: 'Custom local output/artifact folder name. Leave empty to use defaults.'
|
||||
required: false
|
||||
default: ''
|
||||
type: string
|
||||
publish_target_dir:
|
||||
description: 'Remote target directory in sglang-ci-data. Leave empty to use diffusion-ci/consistency_gt/sglang_generated.'
|
||||
required: false
|
||||
default: ''
|
||||
type: string
|
||||
@@ -36,6 +41,7 @@ env:
|
||||
SGLANG_IS_IN_CI: true
|
||||
SGLANG_CUDA_COREDUMP: "1"
|
||||
OUTPUT_NAME: ${{ inputs.output_name || 'diffusion-ci-outputs' }}
|
||||
PUBLISH_TARGET_DIR: ${{ inputs.publish_target_dir || 'diffusion-ci/consistency_gt/sglang_generated' }}
|
||||
|
||||
jobs:
|
||||
compute-diffusion-partitions:
|
||||
@@ -136,7 +142,7 @@ jobs:
|
||||
run: |
|
||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
||||
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||
|
||||
multimodal-diffusion-gen-2gpu:
|
||||
needs: compute-diffusion-partitions
|
||||
@@ -202,7 +208,7 @@ jobs:
|
||||
run: |
|
||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
||||
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||
|
||||
multimodal-diffusion-gen-b200:
|
||||
needs: compute-diffusion-partitions
|
||||
@@ -268,4 +274,4 @@ jobs:
|
||||
run: |
|
||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
||||
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||
|
||||
@@ -561,13 +561,13 @@ Consider updating perf_baselines.json with the snippets below:
|
||||
--- MISSING GROUND TRUTH DETECTED ---
|
||||
GT image(s) not found for '{case.id}'.
|
||||
|
||||
Add the expected file(s) to sglang-ci-data in diffusion-ci/consistency_gt/ with naming (n=num_gpus).
|
||||
Add the expected file(s) to sglang-ci-data in diffusion-ci/consistency_gt/sglang_generated/ with naming (n=num_gpus).
|
||||
Image: {case.id}_{{n}}gpu.<ext> (ext from output_format: png, jpg, webp)
|
||||
Video: {case.id}_{{n}}gpu_frame_0.png, {case.id}_{{n}}gpu_frame_mid.png, {case.id}_{{n}}gpu_frame_last.png
|
||||
|
||||
For this case, expected file(s): {names}
|
||||
|
||||
Repository: https://github.com/sglang-bot/sglang-ci-data (path: diffusion-ci/consistency_gt/)
|
||||
Repository: https://github.com/sglang-bot/sglang-ci-data (path: diffusion-ci/consistency_gt/sglang_generated/)
|
||||
|
||||
(Optional) Per-case override in consistency_threshold.json:
|
||||
"cases": {{
|
||||
|
||||
@@ -33,11 +33,10 @@ logger = init_logger(__name__)
|
||||
|
||||
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/official_generated"
|
||||
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/sglang_generated"
|
||||
SGL_TEST_FILES_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt"
|
||||
SGL_TEST_FILES_CONSISTENCY_GT_BASE = SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE
|
||||
SGL_TEST_FILES_CONSISTENCY_GT_BASES = (
|
||||
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE,
|
||||
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE,
|
||||
SGL_TEST_FILES_CONSISTENCY_GT_BASE,
|
||||
)
|
||||
CONSISTENCY_THRESHOLD_JSON_PATH = (
|
||||
Path(__file__).resolve().parent / "server" / "consistency_threshold.json"
|
||||
|
||||
@@ -4,9 +4,12 @@ via the GitHub API (same pattern as publish_traces.py).
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.error import HTTPError
|
||||
|
||||
# Reuse GitHub API helpers from publish_traces.
|
||||
# Support both direct script execution and package-style imports.
|
||||
@@ -19,6 +22,7 @@ if __package__:
|
||||
get_tree_sha,
|
||||
is_permission_error,
|
||||
is_rate_limit_error,
|
||||
make_github_request,
|
||||
update_branch_ref,
|
||||
verify_token_permissions,
|
||||
)
|
||||
@@ -32,6 +36,7 @@ else:
|
||||
get_tree_sha,
|
||||
is_permission_error,
|
||||
is_rate_limit_error,
|
||||
make_github_request,
|
||||
update_branch_ref,
|
||||
verify_token_permissions,
|
||||
)
|
||||
@@ -39,7 +44,7 @@ else:
|
||||
REPO_OWNER = "sglang-bot"
|
||||
REPO_NAME = "sglang-ci-data"
|
||||
BRANCH = "main"
|
||||
DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt"
|
||||
DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt/sglang_generated"
|
||||
|
||||
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"}
|
||||
|
||||
@@ -61,6 +66,38 @@ def collect_images(source_dir, target_dir):
|
||||
return files
|
||||
|
||||
|
||||
def git_blob_sha(content):
|
||||
header = f"blob {len(content)}\0".encode()
|
||||
return hashlib.sha1(header + content).hexdigest()
|
||||
|
||||
|
||||
def get_remote_blob_shas(repo_owner, repo_name, target_dir, token):
|
||||
url = (
|
||||
f"https://api.github.com/repos/{repo_owner}/{repo_name}/contents/"
|
||||
f"{target_dir}?ref={BRANCH}"
|
||||
)
|
||||
try:
|
||||
response = make_github_request(url, token)
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
return {}
|
||||
raise
|
||||
entries = json.loads(response)
|
||||
return {
|
||||
item["path"]: item["sha"]
|
||||
for item in entries
|
||||
if item.get("type") == "file" and "sha" in item
|
||||
}
|
||||
|
||||
|
||||
def filter_changed_files(files, remote_blob_shas):
|
||||
return [
|
||||
(path, content)
|
||||
for path, content in files
|
||||
if remote_blob_shas.get(path) != git_blob_sha(content)
|
||||
]
|
||||
|
||||
|
||||
def publish(source_dir, target_dir=None):
|
||||
target_dir = target_dir or DEFAULT_TARGET_DIR
|
||||
token = os.getenv("GITHUB_TOKEN")
|
||||
@@ -86,37 +123,48 @@ def publish(source_dir, target_dir=None):
|
||||
print("Token permission verification failed.")
|
||||
sys.exit(1)
|
||||
|
||||
# Create blobs
|
||||
try:
|
||||
tree_items = create_blobs(REPO_OWNER, REPO_NAME, files_to_upload, token)
|
||||
except Exception as e:
|
||||
if is_rate_limit_error(e):
|
||||
print("Rate-limited during blob creation, skipping.")
|
||||
return
|
||||
if is_permission_error(e):
|
||||
print(
|
||||
f"ERROR: Token lacks write permission to {REPO_OWNER}/{REPO_NAME}. "
|
||||
"Update GH_PAT_FOR_NIGHTLY_CI_DATA with a token that has contents:write."
|
||||
)
|
||||
sys.exit(1)
|
||||
raise
|
||||
|
||||
# Commit with retry (handle concurrent pushes)
|
||||
max_retries = 5
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
branch_sha = get_branch_sha(REPO_OWNER, REPO_NAME, BRANCH, token)
|
||||
tree_sha = get_tree_sha(REPO_OWNER, REPO_NAME, branch_sha, token)
|
||||
remote_blob_shas = get_remote_blob_shas(
|
||||
REPO_OWNER, REPO_NAME, target_dir, token
|
||||
)
|
||||
changed_files = filter_changed_files(files_to_upload, remote_blob_shas)
|
||||
if not changed_files:
|
||||
print("No image changes to publish.")
|
||||
return
|
||||
|
||||
try:
|
||||
tree_items = create_blobs(REPO_OWNER, REPO_NAME, changed_files, token)
|
||||
except Exception as e:
|
||||
if is_rate_limit_error(e):
|
||||
print("Rate-limited during blob creation, skipping.")
|
||||
return
|
||||
if is_permission_error(e):
|
||||
print(
|
||||
f"ERROR: Token lacks write permission to {REPO_OWNER}/{REPO_NAME}. "
|
||||
"Update GH_PAT_FOR_NIGHTLY_CI_DATA with a token that has contents:write."
|
||||
)
|
||||
sys.exit(1)
|
||||
raise
|
||||
|
||||
new_tree_sha = create_tree(
|
||||
REPO_OWNER, REPO_NAME, tree_sha, tree_items, token
|
||||
)
|
||||
commit_msg = f"diffusion-ci: update consistency_gt images ({len(files_to_upload)} files) [automated]"
|
||||
if new_tree_sha == tree_sha:
|
||||
print("No tree changes to publish.")
|
||||
return
|
||||
|
||||
commit_msg = f"diffusion-ci: update images in {target_dir} ({len(changed_files)} files) [automated]"
|
||||
commit_sha = create_commit(
|
||||
REPO_OWNER, REPO_NAME, new_tree_sha, branch_sha, commit_msg, token
|
||||
)
|
||||
update_branch_ref(REPO_OWNER, REPO_NAME, BRANCH, commit_sha, token)
|
||||
print(
|
||||
f"Successfully pushed {len(files_to_upload)} images (commit {commit_sha[:10]})"
|
||||
f"Successfully pushed {len(changed_files)} changed images (commit {commit_sha[:10]})"
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
@@ -134,8 +182,6 @@ def publish(source_dir, target_dir=None):
|
||||
elif "Object does not exist" in e.error_body:
|
||||
retryable = True
|
||||
|
||||
from urllib.error import HTTPError
|
||||
|
||||
if isinstance(e, HTTPError) and e.code in [422, 500, 502, 503, 504]:
|
||||
retryable = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user