snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
61
.github/workflows/build-packages.yml
vendored
Normal file
61
.github/workflows/build-packages.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: 📦 Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TURBO_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
with:
|
||||
save-cache: 'true'
|
||||
|
||||
- name: 📦 Build
|
||||
run: pnpm build:ci
|
||||
|
||||
- name: Check for uncommitted changes
|
||||
run: |
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "Error: Uncommitted changes detected after build."
|
||||
echo "Changed files:"
|
||||
git status --porcelain
|
||||
echo "Diff of changes:"
|
||||
git diff
|
||||
exit 1
|
||||
fi
|
||||
128
.github/workflows/ci-quality-checks.yml
vendored
Normal file
128
.github/workflows/ci-quality-checks.yml
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
name: 🧪 CI Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
TURBO_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
test-shard:
|
||||
name: test shard (${{ matrix.shard-index }}/${{ matrix.shard-total }})
|
||||
if: github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
shard-index: [1, 2, 3, 4]
|
||||
shard-total: [4]
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: 🩺 Run test
|
||||
run: node --experimental-strip-types ./scripts/coverage-shard.mts --shard-index=${{ matrix.shard-index }} --shard-total=${{ matrix.shard-total }} --concurrency=2
|
||||
|
||||
- name: 🧬 Report coverage
|
||||
uses: codecov/codecov-action@v7
|
||||
with:
|
||||
name: unit-${{ matrix.shard-index }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
test:
|
||||
name: test
|
||||
if: always() && github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: minimum-runner
|
||||
timeout-minutes: 5
|
||||
needs: test-shard
|
||||
|
||||
steps:
|
||||
- name: Check test shard results
|
||||
run: |
|
||||
if [ "${{ needs.test-shard.result }}" != "success" ]; then
|
||||
echo "One or more test shards failed: ${{ needs.test-shard.result }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All test shards passed"
|
||||
|
||||
eslint:
|
||||
if: github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: Restore ESLint cache
|
||||
id: eslint-cache
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: .eslintcache
|
||||
key: eslint-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'package.json', 'eslint.config.ts') }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
eslint-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'package.json', 'eslint.config.ts') }}-
|
||||
|
||||
- name: 🌡️ Run ESLint
|
||||
run: pnpm lint --quiet --cache --cache-location .eslintcache
|
||||
|
||||
- name: Save ESLint cache
|
||||
if: github.ref_name == github.event.repository.default_branch && steps.eslint-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: .eslintcache
|
||||
key: eslint-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'package.json', 'eslint.config.ts') }}-${{ github.sha }}
|
||||
|
||||
typecheck:
|
||||
if: github.repository == 'dream-num/univer' && (github.event_name != 'pull_request' || !github.event.pull_request.draft)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
|
||||
- name: 🧼 Type checking
|
||||
run: pnpm typecheck
|
||||
65
.github/workflows/collect-pr-metadata.yml
vendored
Normal file
65
.github/workflows/collect-pr-metadata.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: 🎬 Setup
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- closed
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TURBO_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
set-pr-info:
|
||||
name: set PR info
|
||||
if: github.repository == 'dream-num/univer' && !github.event.pull_request.draft
|
||||
runs-on: minimum-runner
|
||||
steps:
|
||||
- name: Save PR info
|
||||
env:
|
||||
PR_ID: ${{ github.event.pull_request.number || '' }}
|
||||
PR_REF: ${{ github.head_ref || github.ref_name }}
|
||||
PR_REPO: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
|
||||
PR_STATE: ${{ github.event.pull_request.state || '' }}
|
||||
run: |
|
||||
printf '%s\n' "$PR_ID" > ./pr-id.txt
|
||||
printf '%s\n' "$PR_REF" > ./pr-ref.txt
|
||||
printf '%s\n' "$PR_REPO" > ./pr-repo.txt
|
||||
printf '%s\n' "$PR_STATE" > ./pr-state.txt
|
||||
|
||||
- name: Upload PR number
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: pr-id
|
||||
path: ./pr-id.txt
|
||||
|
||||
- name: Upload PR ref
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: pr-ref
|
||||
path: ./pr-ref.txt
|
||||
|
||||
- name: Upload PR repo
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: pr-repo
|
||||
path: ./pr-repo.txt
|
||||
|
||||
- name: Upload PR state
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: pr-state
|
||||
path: ./pr-state.txt
|
||||
24
.github/workflows/dispatch-sync-univer-pro.yml
vendored
Normal file
24
.github/workflows/dispatch-sync-univer-pro.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: 🔫 Sync to Pro
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
dispatch-sync:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: minimum-runner
|
||||
|
||||
steps:
|
||||
- name: Dispatch sync event to univer-pro
|
||||
uses: peter-evans/repository-dispatch@v4
|
||||
with:
|
||||
repository: dream-num/univer-pro
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
event-type: sync-univer
|
||||
client-payload: >
|
||||
{
|
||||
"ref": "${{ github.ref_name }}",
|
||||
"sha": "${{ github.sha }}"
|
||||
}
|
||||
62
.github/workflows/release-npm.yml
vendored
Normal file
62
.github/workflows/release-npm.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: 🍰 Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
- 'v*.*.*-alpha.*'
|
||||
- 'v*.*.*-beta.*'
|
||||
- 'v*.*.*-rc.*'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TURBO_TELEMETRY_DISABLED: '1'
|
||||
|
||||
jobs:
|
||||
release-npm:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.ref_name }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install pnpm and Node.js
|
||||
uses: pnpm/setup@v2
|
||||
with:
|
||||
runtime: node@24.3.0
|
||||
install: false
|
||||
|
||||
- name: Configure npm registry
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
registry-url: https://registry.npmjs.org
|
||||
package-manager-cache: false
|
||||
|
||||
- name: 🚚 Install dependencies and build
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
|
||||
- name: 🐙 Publish
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
if [[ "$REF_NAME" =~ -(alpha|beta|rc)\. ]]; then
|
||||
pnpm publish --access public --tag "${BASH_REMATCH[1]}" -r --no-git-checks --provenance
|
||||
else
|
||||
pnpm publish --access public -r --no-git-checks --provenance
|
||||
fi
|
||||
191
.github/workflows/security-semgrep.yml
vendored
Normal file
191
.github/workflows/security-semgrep.yml
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
name: 🔐 Semgrep
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
semgrep:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install Semgrep
|
||||
id: install-semgrep
|
||||
continue-on-error: true
|
||||
run: python -m pip install --upgrade pip semgrep
|
||||
|
||||
- name: Run Semgrep
|
||||
id: semgrep
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
env:
|
||||
INSTALL_OUTCOME: ${{ steps.install-semgrep.outcome }}
|
||||
run: |
|
||||
mkdir -p reports
|
||||
|
||||
if [ "$INSTALL_OUTCOME" = "success" ]; then
|
||||
set +e
|
||||
semgrep scan \
|
||||
--config auto \
|
||||
--sarif \
|
||||
--output reports/semgrep.sarif
|
||||
exit_code=$?
|
||||
set -e
|
||||
else
|
||||
exit_code=2
|
||||
fi
|
||||
|
||||
if [ ! -s reports/semgrep.sarif ]; then
|
||||
printf '%s\n' \
|
||||
'{' \
|
||||
' "version": "2.1.0",' \
|
||||
' "$schema": "https://json.schemastore.org/sarif-2.1.0.json",' \
|
||||
' "runs": [' \
|
||||
' {' \
|
||||
' "tool": {' \
|
||||
' "driver": {' \
|
||||
' "name": "Semgrep",' \
|
||||
' "informationUri": "https://semgrep.dev"' \
|
||||
' }' \
|
||||
' },' \
|
||||
' "invocations": [' \
|
||||
' {' \
|
||||
' "executionSuccessful": false,' \
|
||||
' "toolExecutionNotifications": [' \
|
||||
' {' \
|
||||
' "level": "error",' \
|
||||
' "message": {' \
|
||||
' "text": "Semgrep did not produce a SARIF report. Check the workflow logs for the setup or scan failure."' \
|
||||
' }' \
|
||||
' }' \
|
||||
' ]' \
|
||||
' }' \
|
||||
' ],' \
|
||||
' "results": []' \
|
||||
' }' \
|
||||
' ]' \
|
||||
'}' > reports/semgrep.sarif
|
||||
fi
|
||||
|
||||
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload Semgrep SARIF to GitHub
|
||||
id: upload-sarif
|
||||
if: ${{ always() }}
|
||||
continue-on-error: true
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: reports/semgrep.sarif
|
||||
category: semgrep
|
||||
|
||||
- name: Upload Semgrep report artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: semgrep-sarif-${{ github.run_id }}
|
||||
path: reports/semgrep.sarif
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
- name: Summarize Semgrep report
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
env:
|
||||
SEMGREP_EXIT_CODE: ${{ steps.semgrep.outputs.exit_code }}
|
||||
INSTALL_OUTCOME: ${{ steps.install-semgrep.outcome }}
|
||||
SARIF_UPLOAD_OUTCOME: ${{ steps.upload-sarif.outcome }}
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
report_path = Path("reports/semgrep.sarif")
|
||||
with report_path.open() as file:
|
||||
sarif = json.load(file)
|
||||
|
||||
results = []
|
||||
for run in sarif.get("runs", []):
|
||||
results.extend(run.get("results", []))
|
||||
|
||||
counts = {"error": 0, "warning": 0, "note": 0, "other": 0}
|
||||
for result in results:
|
||||
level = result.get("level", "warning")
|
||||
counts[level if level in counts else "other"] += 1
|
||||
|
||||
sarif_upload_outcome = os.environ.get("SARIF_UPLOAD_OUTCOME") or "skipped"
|
||||
|
||||
with open(os.environ["GITHUB_STEP_SUMMARY"], "a", encoding="utf-8") as summary:
|
||||
summary.write("## Semgrep report\n")
|
||||
summary.write(f"- Total findings: {len(results)}\n")
|
||||
summary.write(f"- Error: {counts['error']}\n")
|
||||
summary.write(f"- Warning: {counts['warning']}\n")
|
||||
summary.write(f"- Note: {counts['note']}\n")
|
||||
summary.write(f"- Other: {counts['other']}\n")
|
||||
summary.write(f"- Exit code: {os.environ['SEMGREP_EXIT_CODE']}\n")
|
||||
summary.write(f"- Semgrep install: {os.environ['INSTALL_OUTCOME']}\n")
|
||||
summary.write("- Artifact: `semgrep-sarif-${{ github.run_id }}`\n")
|
||||
summary.write(f"- Code scanning upload: {sarif_upload_outcome}\n")
|
||||
PY
|
||||
|
||||
- name: Fail on Semgrep error findings or execution errors
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
env:
|
||||
SEMGREP_EXIT_CODE: ${{ steps.semgrep.outputs.exit_code }}
|
||||
run: |
|
||||
if [ -z "$SEMGREP_EXIT_CODE" ]; then
|
||||
echo "Semgrep exit code is missing."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$SEMGREP_EXIT_CODE" -ne 0 ]; then
|
||||
echo "Semgrep execution failed."
|
||||
echo "See the uploaded SARIF artifact for details."
|
||||
exit "$SEMGREP_EXIT_CODE"
|
||||
fi
|
||||
|
||||
python - <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
report_path = Path("reports/semgrep.sarif")
|
||||
with report_path.open() as file:
|
||||
sarif = json.load(file)
|
||||
|
||||
error_results = [
|
||||
result
|
||||
for run in sarif.get("runs", [])
|
||||
for result in run.get("results", [])
|
||||
if result.get("level") == "error"
|
||||
]
|
||||
|
||||
if error_results:
|
||||
print(f"Semgrep reported {len(error_results)} error-level finding(s).")
|
||||
print("See the uploaded SARIF artifact for details.")
|
||||
sys.exit(1)
|
||||
PY
|
||||
21
.github/workflows/sync-gitee-mirror.yml
vendored
Normal file
21
.github/workflows/sync-gitee-mirror.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: 🔮 Sync Mirror
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'dream-num/univer'
|
||||
runs-on: minimum-runner
|
||||
steps:
|
||||
- name: Sync Gitee
|
||||
uses: jikkai/sync-gitee@main
|
||||
with:
|
||||
repository: dream-num/univer
|
||||
username: ${{ secrets.GITEE_USERNAME }}
|
||||
password: ${{ secrets.GITEE_PASSWORD }}
|
||||
tags: true
|
||||
branches: main dev
|
||||
25
.github/workflows/validate-pr-title.yml
vendored
Normal file
25
.github/workflows/validate-pr-title.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: 📌 Check PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: validate PR title
|
||||
if: github.repository == 'dream-num/univer' && !github.event.pull_request.draft
|
||||
runs-on: minimum-runner
|
||||
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
subjectPattern: ^(?![A-Z]).+$
|
||||
Reference in New Issue
Block a user