Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 267 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
PYTHONDONTWRITEBYTECODE: '1'

jobs:
ci:
name: CI required
if: always()
needs: [core, node, offline, android, app]
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- name: Require every job to succeed
env:
CI_JOB_RESULTS: ${{ toJSON(needs) }}
run: python3 Tools/CI/check_jobs.py

app:
name: Main App Release compile (unsigned)
needs: android
runs-on: macos-14
timeout-minutes: 35
env:
DEVELOPER_DIR: /Applications/Xcode_16.2.app/Contents/Developer
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '22.23.0'
- name: Prepare SHA-256 verified XcodeGen
run: |
mkdir -p '${{ runner.temp }}/okvideo-reports/app'
python3 Tools/CI/fetch_tool.py xcodegen --output '${{ runner.temp }}/okvideo-ci-tools' > '${{ runner.temp }}/okvideo-reports/app/tool-download.log' 2>&1
- name: Receive tested compile-only bridge
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: android-compile-input
path: ${{ runner.temp }}/okvideo-android-compile-input
- name: Restore pinned App dependency inputs
id: app-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
${{ runner.temp }}/okvideo-app-dependencies/CrashReporter/Source
${{ runner.temp }}/okvideo-app-dependencies/Downloads
${{ runner.temp }}/okvideo-app-dependencies/SourcePackages
key: app-deps-v1-${{ runner.os }}-${{ runner.arch }}-xcode16.2-${{ hashFiles('OKVideoMac/macOS/OKVideoMac/Packages/OKCrashDiagnostics/Package.swift', 'OKVideoMac/macOS/OKVideoMac/Scripts/prepare-crash-reporter.sh', 'OKVideoMac/macOS/OKVideoMac/Scripts/prepare-sparkle.py', 'ThirdParty/sparkle-lock.json') }}
- name: Compile and verify Release App structure without signing
run: >-
python3 Tools/CI/run_app.py
--work-dir '${{ runner.temp }}/okvideo-app-compile'
--dependencies '${{ runner.temp }}/okvideo-app-dependencies'
--output '${{ runner.temp }}/okvideo-reports/app'
--bridge-input '${{ runner.temp }}/okvideo-android-compile-input'
--xcodegen '${{ runner.temp }}/okvideo-ci-tools/xcodegen'
- name: Retain App compilation evidence only
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: app-compile-${{ github.run_attempt }}
path: ${{ runner.temp }}/okvideo-reports/app/
if-no-files-found: error
retention-days: 7
- name: Save successful main App dependency cache
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.app-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
${{ runner.temp }}/okvideo-app-dependencies/CrashReporter/Source
${{ runner.temp }}/okvideo-app-dependencies/Downloads
${{ runner.temp }}/okvideo-app-dependencies/SourcePackages
key: ${{ steps.app-cache.outputs.cache-primary-key }}

android:
name: Android Release JVM and unsigned bridge
runs-on: ubuntu-24.04
timeout-minutes: 25
env:
GRADLE_USER_HOME: ${{ github.workspace }}/../okvideo-gradle
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: temurin
java-version: '17.0.19+10'
- name: Restore locked Gradle dependencies
id: gradle-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
${{ env.GRADLE_USER_HOME }}/caches
${{ env.GRADLE_USER_HOME }}/wrapper
key: gradle-v1-${{ runner.os }}-${{ runner.arch }}-java17.0.19-${{ hashFiles('OKVideoMac/Helpers/AndroidDexBridge/**/*.gradle', 'OKVideoMac/Helpers/AndroidDexBridge/**/*.lockfile', 'OKVideoMac/Helpers/AndroidDexBridge/gradle/wrapper/gradle-wrapper.properties') }}
- name: Build unsigned bridge and run Release JVM tests
run: >-
python3 Tools/CI/run_android.py
--work-dir '${{ runner.temp }}/okvideo-android'
--output '${{ runner.temp }}/okvideo-reports/android'
--artifact-dir '${{ runner.temp }}/okvideo-android-compile-input'
- name: Retain Android evidence
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: android-tests-${{ github.run_attempt }}
path: ${{ runner.temp }}/okvideo-reports/android/
if-no-files-found: error
retention-days: 7
- name: Transfer compile-only unsigned APK to the App job
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: android-compile-input
path: ${{ runner.temp }}/okvideo-android-compile-input/
if-no-files-found: error
retention-days: 1
overwrite: true
- name: Save successful main Gradle cache
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.gradle-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
${{ env.GRADLE_USER_HOME }}/caches
${{ env.GRADLE_USER_HOME }}/wrapper
key: ${{ steps.gradle-cache.outputs.cache-primary-key }}

offline:
name: Offline audits and static checks
runs-on: macos-14
timeout-minutes: 15
env:
DEVELOPER_DIR: /Applications/Xcode_16.2.app/Contents/Developer
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '22.23.0'
- name: Prepare SHA-256 verified actionlint
run: |
mkdir -p '${{ runner.temp }}/okvideo-reports/offline'
python3 Tools/CI/fetch_tool.py actionlint --output '${{ runner.temp }}/okvideo-ci-tools' > '${{ runner.temp }}/okvideo-reports/offline/tool-download.log' 2>&1
- name: Run all offline audits and static checks
run: >-
python3 Tools/CI/run_offline.py
--output '${{ runner.temp }}/okvideo-reports/offline'
--work-dir '${{ runner.temp }}/okvideo-offline-fixtures'
--actionlint '${{ runner.temp }}/okvideo-ci-tools/actionlint'
- name: Retain offline evidence
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: offline-${{ github.run_attempt }}
path: ${{ runner.temp }}/okvideo-reports/offline/
if-no-files-found: error
retention-days: 7

node:
name: Node
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '22.23.0'
- name: Verify report failure paths
run: python3 Tools/CI/run_python.py --suite ci --output '${{ runner.temp }}/okvideo-reports/node/validator'
- name: Run every Node test file
run: python3 Tools/CI/run_node.py --output '${{ runner.temp }}/okvideo-reports/node'
- name: Retain Node evidence
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: node-${{ github.run_attempt }}
path: ${{ runner.temp }}/okvideo-reports/node/
if-no-files-found: error
retention-days: 7

core:
name: Core (${{ matrix.configuration }})
runs-on: macos-14
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
configuration: [debug, release]
env:
DEVELOPER_DIR: /Applications/Xcode_16.2.app/Contents/Developer
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13.15'
- name: Verify selected toolchain and result-validator failure paths
run: |
test "$(uname -m)" = arm64
xcodebuild -version
swift --version
python3 Tools/CI/run_python.py --suite ci --output '${{ runner.temp }}/okvideo-reports/core-${{ matrix.configuration }}/validator'
- name: Restore configuration-specific build cache
id: core-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ runner.temp }}/okvideo-core-${{ matrix.configuration }}
key: core-v1-${{ runner.os }}-${{ runner.arch }}-xcode16.2-${{ matrix.configuration }}-${{ hashFiles('OKVideoMac/macOS/OKVideoMac/Packages/OKVideoKit/**') }}
- name: Build, discover and run complete suite
run: >-
python3 Tools/CI/run_core.py
--configuration '${{ matrix.configuration }}'
--scratch-path '${{ runner.temp }}/okvideo-core-${{ matrix.configuration }}'
--output '${{ runner.temp }}/okvideo-reports/core-${{ matrix.configuration }}'
--jobs 2
- name: Retain test evidence
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: core-${{ matrix.configuration }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/okvideo-reports/core-${{ matrix.configuration }}/
if-no-files-found: error
retention-days: 7
- name: Save successful main build cache
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.core-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ runner.temp }}/okvideo-core-${{ matrix.configuration }}
key: ${{ steps.core-cache.outputs.cache-primary-key }}
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

## [Unreleased]

No additional changes beyond 0.9.0.
- Add credential-free CI for Core/Persistence Debug and Release, all Node tests, offline audits/static checks, Android Release JVM tests and unsigned main App Release compilation; retain reports and require every job to succeed.
- Pin CI Actions and tool downloads, isolate build inputs, validate discovered/completed test results and allowed skips, and reject empty, incomplete or failed results. Verify the aggregate gate with an intentional failure in an isolated branch.
- Make crash-worker tests respect the selected Xcode, replace TMDB test timing sleeps with explicit coordination, publish the loopback fixture port atomically, and preserve Python class-fixture errors in reports.
- Document CI coverage, local reproduction and remaining limits. App version/build and existing v0.9.0 release assets remain unchanged.

## [0.9.0] - 2026-10-26

Expand Down
15 changes: 12 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ PR 保持单一、清晰的范围。说明变更目的、验证方式以及已
- 影响许可、对应源码、SBOM 或 provenance 的变更必须同步更新相应记录;
- 不要把未经验证的第三方 artifact 作为可发布二进制提交。

仓库没有在本文件中承诺特定 CI 必过项;maintainer 会根据变更风险要求补充验证。
发布包仍必须遵循 `Docs/SOURCE_RELEASE_PROCESS.md` 和仓库 release scripts 的
fail-closed 检查。
提交到 `main` 的 PR 和 `main` 推送会运行 [CI](.github/workflows/ci.yml)。合入前应确认
`CI required` 及其依赖的 Core Debug/Release、Node、离线审计与静态检查、Android JVM
测试、主 App 无签名 Release 编译全部通过。失败、取消、跳过任务或缺失结果都不能
视为通过。该汇总检查不等于已启用 GitHub 分支保护;本轮没有修改仓库保护规则。

运行方法、工具版本、报告和明确不覆盖的范围见 [CI 指南](Docs/CI.md)。Core 中既有的
条件测试跳过项由测试名和原因白名单约束,不得通过扩大跳过范围掩盖失败。新增测试
会自动发现;更改白名单需解释对应的环境要求,并保留相关的人工验收路径。

维护者仍会按变更风险要求补充实机、播放、兼容性或真实服务验证。CI 的未签名编译
产物仅用于检查,不能安装或发布。发布包必须遵循
[正式发布流程](Docs/SOURCE_RELEASE_PROCESS.md)和仓库 release scripts 的 fail-closed 检查。
Loading
Loading