[diffusion] CI: change ground truth upload path and improve publish script (#24120)

This commit is contained in:
Mick
2026-04-30 12:26:10 +08:00
committed by GitHub
parent c54ada994b
commit 0b1fbdba15
4 changed files with 79 additions and 28 deletions
+10 -4
View File
@@ -14,7 +14,12 @@ on:
default: '' default: ''
type: string type: string
output_name: 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 required: false
default: '' default: ''
type: string type: string
@@ -36,6 +41,7 @@ env:
SGLANG_IS_IN_CI: true SGLANG_IS_IN_CI: true
SGLANG_CUDA_COREDUMP: "1" SGLANG_CUDA_COREDUMP: "1"
OUTPUT_NAME: ${{ inputs.output_name || 'diffusion-ci-outputs' }} OUTPUT_NAME: ${{ inputs.output_name || 'diffusion-ci-outputs' }}
PUBLISH_TARGET_DIR: ${{ inputs.publish_target_dir || 'diffusion-ci/consistency_gt/sglang_generated' }}
jobs: jobs:
compute-diffusion-partitions: compute-diffusion-partitions:
@@ -136,7 +142,7 @@ jobs:
run: | run: |
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \ python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
--source-dir python/${{ env.OUTPUT_NAME }} \ --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: multimodal-diffusion-gen-2gpu:
needs: compute-diffusion-partitions needs: compute-diffusion-partitions
@@ -202,7 +208,7 @@ jobs:
run: | run: |
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \ python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
--source-dir python/${{ env.OUTPUT_NAME }} \ --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: multimodal-diffusion-gen-b200:
needs: compute-diffusion-partitions needs: compute-diffusion-partitions
@@ -268,4 +274,4 @@ jobs:
run: | run: |
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \ python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
--source-dir python/${{ env.OUTPUT_NAME }} \ --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 --- --- MISSING GROUND TRUTH DETECTED ---
GT image(s) not found for '{case.id}'. 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) 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 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} 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: (Optional) Per-case override in consistency_threshold.json:
"cases": {{ "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_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_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_CONSISTENCY_GT_BASES = (
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE, SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE,
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE, SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE,
SGL_TEST_FILES_CONSISTENCY_GT_BASE,
) )
CONSISTENCY_THRESHOLD_JSON_PATH = ( CONSISTENCY_THRESHOLD_JSON_PATH = (
Path(__file__).resolve().parent / "server" / "consistency_threshold.json" 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 argparse
import hashlib
import json
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
from urllib.error import HTTPError
# Reuse GitHub API helpers from publish_traces. # Reuse GitHub API helpers from publish_traces.
# Support both direct script execution and package-style imports. # Support both direct script execution and package-style imports.
@@ -19,6 +22,7 @@ if __package__:
get_tree_sha, get_tree_sha,
is_permission_error, is_permission_error,
is_rate_limit_error, is_rate_limit_error,
make_github_request,
update_branch_ref, update_branch_ref,
verify_token_permissions, verify_token_permissions,
) )
@@ -32,6 +36,7 @@ else:
get_tree_sha, get_tree_sha,
is_permission_error, is_permission_error,
is_rate_limit_error, is_rate_limit_error,
make_github_request,
update_branch_ref, update_branch_ref,
verify_token_permissions, verify_token_permissions,
) )
@@ -39,7 +44,7 @@ else:
REPO_OWNER = "sglang-bot" REPO_OWNER = "sglang-bot"
REPO_NAME = "sglang-ci-data" REPO_NAME = "sglang-ci-data"
BRANCH = "main" BRANCH = "main"
DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt" DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt/sglang_generated"
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"} IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"}
@@ -61,6 +66,38 @@ def collect_images(source_dir, target_dir):
return files 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): def publish(source_dir, target_dir=None):
target_dir = target_dir or DEFAULT_TARGET_DIR target_dir = target_dir or DEFAULT_TARGET_DIR
token = os.getenv("GITHUB_TOKEN") token = os.getenv("GITHUB_TOKEN")
@@ -86,9 +123,22 @@ def publish(source_dir, target_dir=None):
print("Token permission verification failed.") print("Token permission verification failed.")
sys.exit(1) sys.exit(1)
# Create blobs # Commit with retry (handle concurrent pushes)
max_retries = 5
for attempt in range(max_retries):
try: try:
tree_items = create_blobs(REPO_OWNER, REPO_NAME, files_to_upload, token) 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: except Exception as e:
if is_rate_limit_error(e): if is_rate_limit_error(e):
print("Rate-limited during blob creation, skipping.") print("Rate-limited during blob creation, skipping.")
@@ -101,22 +151,20 @@ def publish(source_dir, target_dir=None):
sys.exit(1) sys.exit(1)
raise 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)
new_tree_sha = create_tree( new_tree_sha = create_tree(
REPO_OWNER, REPO_NAME, tree_sha, tree_items, token 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( commit_sha = create_commit(
REPO_OWNER, REPO_NAME, new_tree_sha, branch_sha, commit_msg, token REPO_OWNER, REPO_NAME, new_tree_sha, branch_sha, commit_msg, token
) )
update_branch_ref(REPO_OWNER, REPO_NAME, BRANCH, commit_sha, token) update_branch_ref(REPO_OWNER, REPO_NAME, BRANCH, commit_sha, token)
print( 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 return
except Exception as e: except Exception as e:
@@ -134,8 +182,6 @@ def publish(source_dir, target_dir=None):
elif "Object does not exist" in e.error_body: elif "Object does not exist" in e.error_body:
retryable = True retryable = True
from urllib.error import HTTPError
if isinstance(e, HTTPError) and e.code in [422, 500, 502, 503, 504]: if isinstance(e, HTTPError) and e.code in [422, 500, 502, 503, 504]:
retryable = True retryable = True