feat: add manifest-driven batch rebuild, numpy cross-compilation, and CI pipeline updates
Some checks failed
EcoArk Wheel Pipeline CI / build (push) Failing after 1m41s

- Add pipeline/manifest.py for packages.txt parsing
- Implement real numpy cross-compilation (rebuild.py) with OHOS NDK + vendored meson
- Extend CLI with --manifest, --build-from-source, --stage-integration modes
- Add recipes/, experiments/, and scripts/ for integration staging and artifact upload
- Update CI workflow with manifest validation, artifact upload, and release publishing
- Update Makefile and README with new targets and documentation
This commit is contained in:
root
2026-05-13 14:16:24 +08:00
parent cdc816467d
commit 553b83953c
15 changed files with 1310 additions and 99 deletions

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""
Upload build outputs as Gitea Actions artifacts using the Actions Runtime API.
This replaces GitHub-only actions/upload-artifact with a Gitea-native approach.
Uses ACTIONS_RUNTIME_URL and ACTIONS_RUNTIME_TOKEN provided by Gitea's
act_runner to upload artifacts directly to the pipeline service.
Usage:
python3 scripts/upload_artifacts.py <artifact_name> <path_glob1> [path_glob2 ...]
Environment (set by Gitea act_runner >= 1.21):
ACTIONS_RUNTIME_URL — Pipeline service base URL (e.g. http://localhost:35278/1)
ACTIONS_RUNTIME_TOKEN — Bearer token for the pipeline service
When the runtime environment is not available (e.g. local testing),
artifacts are saved to ./artifacts/<name>.zip as a fallback.
"""
import glob
import io
import os
import sys
import urllib.error
import urllib.request
import zipfile
_RUNTIME_UPLOADED = False
def _upload_via_runtime(name, payload, runtime_url, runtime_token):
url = "{}/_apis/pipeline/artifacts/{}".format(runtime_url.rstrip("/"), name)
headers = {
"Authorization": "Bearer " + runtime_token,
"Content-Type": "application/octet-stream",
"Content-Range": "bytes 0-{}/{}".format(len(payload) - 1, len(payload)),
"x-tfs-filelength": str(len(payload)),
}
req = urllib.request.Request(url, data=payload, headers=headers, method="PUT")
try:
with urllib.request.urlopen(req) as resp:
msg = "[upload-artifact] Uploaded '{}' ({} bytes) to Gitea runtime — HTTP {}"
print(msg.format(name, len(payload), resp.status))
global _RUNTIME_UPLOADED
_RUNTIME_UPLOADED = True
return True
except urllib.error.HTTPError as e:
body = e.read().decode()[:300] if e.fp else ""
print("[upload-artifact] Runtime upload failed: HTTP {}{}".format(e.code, body))
return False
def _save_locally(name, payload):
dest = os.path.join("artifacts", "{}.zip".format(name))
os.makedirs(os.path.dirname(dest) or ".", exist_ok=True)
with open(dest, "wb") as f:
f.write(payload)
print("[upload-artifact] Saved artifact to {} ({} bytes)".format(dest, len(payload)))
def main():
if len(sys.argv) < 3:
print("Usage: {} <artifact_name> <path_glob> [path_glob ...]".format(sys.argv[0]))
sys.exit(1)
artifact_name = sys.argv[1]
patterns = sys.argv[2:]
files = []
for pattern in patterns:
matched = glob.glob(pattern, recursive=True)
files.extend(matched)
files = sorted(set(f for f in files if os.path.isfile(f)))
if not files:
print("[upload-artifact] No files found for pattern(s): {}".format(patterns))
return
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
for f in files:
zf.write(f, os.path.relpath(f))
payload = buf.getvalue()
runtime_url = os.environ.get("ACTIONS_RUNTIME_URL", "").rstrip("/")
runtime_token = os.environ.get("ACTIONS_RUNTIME_TOKEN", "")
if runtime_url and runtime_token:
ok = _upload_via_runtime(artifact_name, payload, runtime_url, runtime_token)
if not ok:
_save_locally(artifact_name, payload)
else:
print("[upload-artifact] ACTIONS_RUNTIME_URL/TOKEN not available — saving locally.")
_save_locally(artifact_name, payload)
print("[upload-artifact] Done — {} file(s) in '{}'.".format(len(files), artifact_name))
if __name__ == "__main__":
main()