OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)

This commit is contained in:
wangruiguo
2026-09-03 18:49:20 +08:00
commit d647428529
3501 changed files with 1988906 additions and 0 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @leantime/developers

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: ['Leantime']
custom: ['https://marketplace.leantime.io']

52
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Bug Report
description: File a bug report.
title: "Enter a title of your bug"
type: "Bug"
assignees:
- marcelfolaron
body:
- type: markdown
attributes:
value: "Thank you for taking the time to submit a bug report. If you have problems with the installation or other questions please use the [discussion forum](https://github.com/Leantime/leantime/discussions) or our [discord server](https://discord.gg/4zMzJtAq9z)"
- type: dropdown
attributes:
label: What is your set up?
options:
- Cloud Hosted
- Self Hosted Server
- Self Hosted Docker
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: "Which Leantime version are you using (see footer bottom right)"
placeholder: "3.x.x"
validations:
required: true
- type: textarea
attributes:
label: Describe the issue
placeholder: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: repro
attributes:
label: Reproduction steps
description: "How do you trigger this bug? Please walk us through it step by step."
value: |
1.
2.
3.
...
validations:
required: true
- type: textarea
id: context
attributes:
label: Error Logs (LEANTIMEFOLDER/storage/logs)
description: "Please past the contents of your error logs and any other logs you may have."
validations:
required: false

View File

@@ -0,0 +1,36 @@
name: Feature request
description: Suggest an idea for this project.
title: "Enter title of your feature suggestion"
type: "Feature"
assignees:
- marcelfolaron
body:
- type: markdown
attributes:
value: "Thank you for taking the time to submit a feature request. If you have problems with the installation or other questions please use the [discussion forum](https://github.com/Leantime/leantime/discussions) or our [discord server](https://discord.gg/4zMzJtAq9z)"
- type: dropdown
attributes:
label: What is your set up?
options:
- Cloud Hosted
- Self Hosted Server
- Self Hosted Docker
validations:
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe
description: A clear and concise description of what the problem is.
placeholder: Ex. I'm always frustrated when [...]
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
placeholder:
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: "Add any other context or screenshots about the feature request here."
validations:

17
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,17 @@
### Description
*Please include a short description of the suggested change and the reasoning behind the approach you have chosen.*
### Link to ticket
*Please add a link to the GitHub issue being addressed by this change.*
### Type
- [ ] Fix
- [ ] Feature
- [ ] Cleanup
### Screenshot of the result
*If your change affects the user interface, you should include a screenshot of the result with the pull request.*

31
.github/changelogConfig.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
changelog_type: 'commit_message'
header_prefix: 'Version:'
commit_changelog: true
comment_changelog: true
include_unlabeled_changes: true
unlabeled_group_title: 'Unlabeled Changes'
pull_request_title_regex: '^Release'
version_regex: 'v?([0-9]{1,2})+[.]+([0-9]{1,2})+[.]+([0-9]{1,2})\s\(\d{1,2}-\d{1,2}-\d{4}\)'
exclude_labels:
- bot
- dependabot
- ci
group_config:
- title: Bug Fixes
labels:
- bug
- bugfix
- fix
- title: Code Improvements
labels:
- improvements
- enhancement
- cleanup
- title: New Features
labels:
- feature
- title: Documentation Updates
labels:
- docs
- documentation
- doc

17
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
changelog:
exclude:
labels:
- ignore-for-release
categories:
- title: 🛠 Breaking Changes
labels:
- Breaking-Change
- title: 🎉 New Features
labels:
- Feature
- title: 🐞 Bug Fixes
labels:
- Bug
- title: Other Changes
labels:
- "*"

30
.github/workflows/acceptancetests.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Acceptance Tests (Selenium)
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
acceptance:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Run Acceptance Tests
run: make acceptance-test-ci
- name: Store screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: acceptance-test
path: tests/_output

36
.github/workflows/api-bearer-tests.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: API Tests (Bearer auth)
# Sibling to acceptancetests.yml. Exists because the JSON-RPC endpoint
# accepts three auth modes (session, x-api-key, Bearer) and ApiCest only
# exercises x-api-key. Bearer is the mode mobile + AdvancedAuth integrators
# hit, and a 2026-06 permission-engine deploy silently broke it for every
# gated read with no CI signal. This workflow closes that gap.
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
bearer-api:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Run Bearer API Tests
run: make bearer-api-test-ci
- name: Store screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: bearer-api-test
path: tests/_output

28
.github/workflows/codeStyleAnalysis.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Code Style Analysis
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
pint:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Install Dependencies
run: make build-dev
- name: Run Laravel Pint Analysis
run: make test-code-style

28
.github/workflows/makefile.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Makefile CI
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Install dependencies
run: make build
- name: Run distcheck
run: make clean

174
.github/workflows/release-prepare.yml vendored Normal file
View File

@@ -0,0 +1,174 @@
name: Prepare Release
# Dispatch with a version number to open a "Release vX.Y.Z" PR containing the
# version bump (package.json, package-lock.json, AppSettings.php) and an
# AI-drafted CHANGELOG.md section. The regular CI suite runs on the PR as the
# final test gate; merging the PR triggers the Create Release workflow which
# tags, packages, and publishes.
#
# Requires two repo secrets:
# - RELEASE_TOKEN: fine-grained PAT with Contents + Pull requests read/write.
# PRs opened with the default GITHUB_TOKEN would not trigger CI workflows.
# - ANTHROPIC_API_KEY: Claude API key used to draft the changelog section.
on:
workflow_dispatch:
inputs:
version:
description: 'New version number (e.g. 3.8.1)'
required: true
type: string
# Least privilege: branch push + PR creation use the RELEASE_TOKEN PAT, so the
# default token only needs read access (checkout, changelog).
permissions:
contents: read
pull-requests: read
jobs:
prepare:
runs-on: ubuntu-latest
env:
VERSION: ${{ inputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Validate version
run: |
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Version '$VERSION' is not a valid X.Y.Z version number"
exit 1
fi
CURRENT=$(make get-version)
if [ "$VERSION" = "$CURRENT" ]; then
echo "::error::Version $VERSION is already the current version"
exit 1
fi
if git rev-parse -q --verify "refs/tags/v$VERSION" > /dev/null; then
echo "::error::Tag v$VERSION already exists"
exit 1
fi
- name: Bump version files
run: |
npm version "$VERSION" --no-git-tag-version
sed -i "s/appVersion = '[^']*'/appVersion = '$VERSION'/" app/Core/Configuration/AppSettings.php
echo "Bumped to $(make get-version)"
- name: Collect history since last release
run: |
LAST_TAG=$(git describe --tags --abbrev=0 --match 'v*')
echo "Generating changelog for $LAST_TAG..HEAD"
git log "$LAST_TAG"..HEAD --no-merges --pretty='- %s' > "$RUNNER_TEMP/commits.md"
wc -l "$RUNNER_TEMP/commits.md"
- name: Build changelog prompt
run: |
# Most recent CHANGELOG section doubles as the style example
awk '/^# Version:/{n++} n==1' CHANGELOG.md > "$RUNNER_TEMP/style-example.md"
cat > "$RUNNER_TEMP/system-prompt.md" << 'SYSEOF'
You are the release manager for Leantime, an open source project management
system. You write the CHANGELOG.md section for a new release based on the
git commit subjects since the last release.
Format rules:
- Start with exactly: # Version: <version>
- Use these sections, in this order, and ONLY if they have content:
## Highlights, ## New Features, ## Bug Fixes, ## Improvements, ## Security, ## Localization, ## Dependency Updates
- Highlights: at most 1-3 entries, only for genuinely notable user-facing
features (### subheading + a short paragraph). Most releases have none -
omit the section rather than inflate minor work.
- All other entries are single bullets: **Short Title** - one-sentence
user-facing description ending with the PR reference(s), e.g. (#1234)
- Rewrite commit subjects into user-facing language; never copy
conventional-commit prefixes like fix(scope): into the output.
- Merge multiple commits about the same change into one bullet with all
PR references.
- Group dependency bumps into ## Dependency Updates as terse bullets.
- Skip pure chores with no user impact (CI tweaks, code style, review
follow-up commits that have no PR reference).
- Output raw markdown only - no surrounding code fences, no commentary.
Here is the previous release's section as a style example:
SYSEOF
cat "$RUNNER_TEMP/style-example.md" >> "$RUNNER_TEMP/system-prompt.md"
{
echo "Write the CHANGELOG section for version $VERSION based on these commits:"
echo
cat "$RUNNER_TEMP/commits.md"
} > "$RUNNER_TEMP/prompt.md"
- name: Generate changelog section
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "::error::ANTHROPIC_API_KEY secret is not set"
exit 1
fi
jq -n \
--rawfile system "$RUNNER_TEMP/system-prompt.md" \
--rawfile prompt "$RUNNER_TEMP/prompt.md" \
'{
model: "claude-opus-4-8",
max_tokens: 8000,
thinking: {type: "adaptive"},
system: $system,
messages: [{role: "user", content: $prompt}]
}' > "$RUNNER_TEMP/request.json"
if ! curl -sS --fail-with-body --max-time 600 https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d @"$RUNNER_TEMP/request.json" > "$RUNNER_TEMP/response.json"; then
echo "::error::Anthropic API request failed"
cat "$RUNNER_TEMP/response.json"
exit 1
fi
# Adaptive thinking responses interleave thinking blocks - keep text blocks only
jq -r '[.content[] | select(.type == "text") | .text] | join("\n")' \
"$RUNNER_TEMP/response.json" > "$RUNNER_TEMP/ai-response.md"
if ! [ -s "$RUNNER_TEMP/ai-response.md" ]; then
echo "::error::Empty changelog from the API (stop_reason: $(jq -r '.stop_reason' "$RUNNER_TEMP/response.json"))"
exit 1
fi
- name: Prepend section to CHANGELOG.md
run: |
sed '/^```/d' "$RUNNER_TEMP/ai-response.md" > "$RUNNER_TEMP/new-section.md"
if ! head -1 "$RUNNER_TEMP/new-section.md" | grep -q "^# Version: $VERSION"; then
printf '# Version: %s\n\n' "$VERSION" | cat - "$RUNNER_TEMP/new-section.md" > "$RUNNER_TEMP/new-section.tmp"
mv "$RUNNER_TEMP/new-section.tmp" "$RUNNER_TEMP/new-section.md"
fi
{ cat "$RUNNER_TEMP/new-section.md"; echo; echo '---'; echo; cat CHANGELOG.md; } > "$RUNNER_TEMP/changelog.md"
mv "$RUNNER_TEMP/changelog.md" CHANGELOG.md
{
echo "Automated release PR. Review and edit the changelog below (it ships as CHANGELOG.md and as the GitHub release notes), wait for CI, then merge - the release publishes automatically."
echo
echo '---'
echo
cat "$RUNNER_TEMP/new-section.md"
} > "$RUNNER_TEMP/pr-body.md"
- name: Open release PR
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.RELEASE_TOKEN }}
commit-message: 'release: bump version to ${{ inputs.version }} + changelog'
branch: release/v${{ inputs.version }}
delete-branch: true
base: master
title: 'Release v${{ inputs.version }}'
labels: release
body-path: ${{ runner.temp }}/pr-body.md

81
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,81 @@
name: Create Release
# Runs automatically when a release/vX.Y.Z PR (opened by the Prepare Release
# workflow) is merged into master. Manual escape hatches: dispatch directly or
# push a version tag - both release whatever version AppSettings.php declares.
on:
workflow_dispatch:
push:
tags:
- '*'
pull_request:
types: [closed]
branches:
- master
permissions:
contents: write
jobs:
build_release:
name: build_release
if: github.event_name != 'pull_request' || (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/'))
runs-on: ubuntu-24.04
steps:
# On pull_request events github.sha points at a transient PR merge ref,
# not the commit that landed on master - build and tag merge_commit_sha.
- name: checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.merge_commit_sha || github.ref }}
# Same PHP setup as Makefile CI - the runner's stock ext-redis (5.3.7)
# conflicts with symfony/cache >= 7.4, which requires ext-redis >= 6.1.
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: version
run: echo "version=$(make get-version)" >> $GITHUB_OUTPUT
id: version
# COMPOSER_AUTH prevents GitHub API rate-limiting; without it composer silently
# falls back to source (git clone) installs, shipping .git dirs and package build/
# test artifacts that ballooned release archives (#3330).
- name: build artifacts
run: make package
env:
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ github.token }}"}}'
- name: Extract changelog section
run: |
awk '/^# Version:/{n++} n==1' CHANGELOG.md > "$RUNNER_TEMP/release-body.md"
if ! grep -q "Version: ${{ steps.version.outputs.version }}" "$RUNNER_TEMP/release-body.md"; then
echo "::warning::Top CHANGELOG.md section does not match v${{ steps.version.outputs.version }}; falling back to auto-generated notes only"
: > "$RUNNER_TEMP/release-body.md"
fi
- name: release
uses: ncipollo/release-action@v1
id: create_release
with:
token: ${{ github.token }}
draft: false
prerelease: false
name: Leantime v${{ steps.version.outputs.version }}
tag: v${{ steps.version.outputs.version }}
commit: ${{ github.event_name == 'pull_request' && github.event.pull_request.merge_commit_sha || github.sha }}
generateReleaseNotes: true
makeLatest: true
bodyFile: ${{ runner.temp }}/release-body.md
artifacts: './target/Leantime-v${{ steps.version.outputs.version }}.zip,./target/Leantime-v${{ steps.version.outputs.version }}.tar.gz'
- name: Run latest-tag
uses: EndBug/latest-tag@latest
with:
ref: latest
description: Latest Release of Leantime.

63
.github/workflows/security.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: Security Audit
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
schedule:
- cron: '0 8 * * 1' # Weekly on Monday at 8am UTC
jobs:
composer-audit:
name: Composer Security Audit
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Install Composer Dependencies
run: composer install --no-dev --no-interaction --prefer-dist
- name: Run Composer Audit
run: composer audit --format=summary
continue-on-error: true
npm-audit:
name: NPM Security Audit
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install NPM Dependencies
run: npm ci
- name: Run NPM Audit
run: npm audit --audit-level=high
codeql:
name: CodeQL Analysis
runs-on: ubuntu-24.04
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

26
.github/workflows/staticAnalysis.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Static Analysis
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
phpstan:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Install Dependencies
run: make build-dev
- name: Run PHPStan Analysis
run: make phpstan

30
.github/workflows/unittests.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Unit Tests
on:
workflow_dispatch:
push:
branches: [ "master", "*.*-dev" ]
pull_request:
branches: [ "master", "*.*-dev" ]
jobs:
unit:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: redis, gd, ldap, mbstring, pdo_mysql, zip, bcmath, exif, pcntl
- name: Run Unit Tests
run: make unit-test
- name: Store screenshots
uses: actions/upload-artifact@v4
if: failure()
with:
name: unit-test
path: tests/_output

32
.github/workflows/update-latest-tag.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Updated Latest Tag
on:
workflow_dispatch:
jobs:
build_release:
name: build_release
runs-on: ubuntu-24.04
steps:
- name: checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Run latest-tag
uses: EndBug/latest-tag@latest
with:
# You can change the name of the tag or branch with this input.
# Default: 'latest'
ref: latest
# If a description is provided, the action will use it to create an annotated tag. If none is given, the action will create a lightweight tag.
# Default: ''
description: Latest Release of Leantime.
# Force-update a branch instead of using a tag.
# Default: false
# force-branch: true
# Directory to use when executing git commands
# Default: '${{ github.workspace }}'
# git-directory: 'path/to/repo/dir'